【问题标题】:JsonParseException: Invalid UTF-8 middle byte 0x20 with MockMVC and MavenJsonParseException:使用 MockMVC 和 Maven 的 UTF-8 中间字节 0x20 无效
【发布时间】:2016-02-24 09:05:08
【问题描述】:

编辑:如果我删除 spring-restdoc 代码,则测试通过 maven。


我正在尝试在 Spring Boot Web 应用程序中使用 MockMVC 编写集成测试。

如果我在 IDE 中运行它,我目前只有一个测试(下面的步骤和代码)通过,但如果由 Maven 执行,则会失败并显示以下堆栈跟踪:

org.springframework.restdocs.payload.PayloadHandlingException: com.fasterxml.jackson.core.JsonParseException: Invalid UTF-8 middle byte 0x20
 at [Source: [B@3793896e; line: 30, column: 23]
        at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1419)
        at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:508)
        at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._reportInvalidOther(UTF8StreamJsonParser.java:3223)
        at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._reportInvalidOther(UTF8StreamJsonParser.java:3230)
        at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._decodeUtf8_3fast(UTF8StreamJsonParser.java:3036)
        at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._finishString2(UTF8StreamJsonParser.java:2216)
        at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._finishString(UTF8StreamJsonParser.java:2165)
        at com.fasterxml.jackson.core.json.UTF8StreamJsonParser.getText(UTF8StreamJsonParser.java:279)
        at com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer$Vanilla.deserialize(UntypedObjectDeserializer.java:441)
        at com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer$Vanilla.mapObject(UntypedObjectDeserializer.java:574)
        at com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer$Vanilla.deserialize(UntypedObjectDeserializer.java:423)
        at com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer$Vanilla.mapArray(UntypedObjectDeserializer.java:510)
        at com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer$Vanilla.deserialize(UntypedObjectDeserializer.java:437)
        at com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer$Vanilla.mapObject(UntypedObjectDeserializer.java:552)
        at com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer$Vanilla.deserialize(UntypedObjectDeserializer.java:423)
        at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3066)
        at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2230)
        at org.springframework.restdocs.payload.JsonContentHandler.readContent(JsonContentHandler.java:81)
        at org.springframework.restdocs.payload.JsonContentHandler.findMissingFields(JsonContentHandler.java:49)
        at org.springframework.restdocs.payload.AbstractFieldsSnippet.validateFieldDocumentation(AbstractFieldsSnippet.java:112)
        at org.springframework.restdocs.payload.AbstractFieldsSnippet.createModel(AbstractFieldsSnippet.java:73)
        at org.springframework.restdocs.snippet.TemplatedSnippet.document(TemplatedSnippet.java:64)
        at org.springframework.restdocs.mockmvc.RestDocumentationResultHandler.handle(RestDocumentationResultHandler.java:101)
        at org.springframework.test.web.servlet.MockMvc$1.andDo(MockMvc.java:158)

代码:

我添加了 starter-test 依赖项,并为所有未来的测试创建了一个超类:

@Ignore
@MappedSuperclass
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
@ActiveProfiles(value = {"test"})
public class IntegrationTest
{
    @Autowired
    WebApplicationContext context;

    MockMvc mockMvc;

    @Rule
    public RestDocumentation restDocumentation = new RestDocumentation("target/generated-snippets");

    @Before
    public void setUp()
    {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context).apply(documentationConfiguration(this.restDocumentation)).build();
    }
}

然后我创建了这个测试:

public class PostsTest extends IntegrationTest
{
    @Test
    public void getAll() throws Exception
    {
        mockMvc.perform(get("/api/v1/posts").accept(MediaType.APPLICATION_JSON_VALUE)
            .andExpect(status().isOk())
            .andDo(document("posts-index", preprocessResponse(prettyPrint()), responseFields(
                fieldWithPath("data").description("The response payload"),
                fieldWithPath("data.[].id").description("ID"),
                fieldWithPath("data.[].title").description("Title"),
                fieldWithPath("data.[].body").description("Content"),
                fieldWithPath("data.[].type").description("Type"),
                fieldWithPath("data.[].createdAt").description("Creation date"),
                fieldWithPath("data.[].modifiedAt").description("Last edit date"),
                fieldWithPath("data.[].entityType").description("Entity type"),
                fieldWithPath("meta").description("The response metadata")
            )));
    }
}

【问题讨论】:

    标签: java spring maven jackson spring-restdocs


    【解决方案1】:

    我发现从 restdocs 代码中删除 preprocessResponse(prettyPrint()),测试通过了。

    编辑:正如 Andy Wilkinson 在 cmets 中所报告的,此错误已通过 1.0.2.BUILD-SNAPSHOTspring-restdocs 版本修复。

    【讨论】:

    • 听起来像this bug。它已在 1.0.2 快照中修复。如果您想尝试一下,可以从repo.spring.io/libs-snapshot 获得它们。使用1.0.2.BUILD-SNAPSHOT 作为版本。
    • 没错。它适用于快照版本。谢谢!
    【解决方案2】:

    您在某个时候正在解析 json,我怀疑它是从文件中读取的。

    该文件似乎以错误的编码保存,例如 ISO-8859-1。确保它以 UTF-8、UTF-16 或 UTF-32 格式保存。大多数 JSON 解析器都是从前四个字节猜测编码,如果发现不支持的编码就会失败。

    【讨论】:

    • 数据是从 MySQL 数据库中提取的。我不明白的是maven和IDE之间的区别。
    • IDE 可能使用 UTF-8,而 maven 在命令提示符下运行时使用平台编码(在 Windows 机器上仍然是 ISO-8859-1 或 Latin1)。尝试将-Dfile.encoding="UTF-8" 添加到您的命令行语句中,看看它是否有任何改变。
    • 什么都没有改变,我的 pom 中已经有了<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    • 问题是从数据库中读取。我建议的选项和您在 pom.xml 中的设置不会影响数据库的内容...您可以发布从数据库读取 json 所涉及的代码吗?
    • 我使用 Spring Data 和 Spring MVC,所以模型被 Jackson 序列化为 JSON。 (我编辑了这个问题,因为如果我删除 spring-restdoc 代码,测试通过 maven。)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-14
    相关资源
    最近更新 更多