JsonParseException: неверный средний байт UTF-8 0x20 с MockMVC и Maven

EDIT: если я удалю код spring-restdoc, тест пройдет с maven.


Я пытаюсь написать интеграционный тест с MockMVC в веб-приложении Spring Boot.

На данный момент у меня есть только один тест (шаги и код ниже), который проходит, если я запускаю его в среде 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)

Код:

Я добавил зависимость start-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")
            )));
    }
}

person Francesco Papagno    schedule 24.02.2016    source источник


Ответы (2)


Выяснил, что удаляя preprocessResponse(prettyPrint()) из кода restdocs, тест проходит.

EDIT: как сообщил Энди Уилкинсон в комментариях, эта ошибка исправлена ​​в версии 1.0.2.BUILD-SNAPSHOT из spring-restdocs.

person Francesco Papagno    schedule 24.02.2016
comment
Похоже на эту ошибку. Это было исправлено в снапшотах версии 1.0.2. Они доступны на repo.spring.io/libs-snapshot, если вы хотите попробуйте. Используйте 1.0.2.BUILD-SNAPSHOT в качестве версии. - person Andy Wilkinson; 24.02.2016
comment
Это правильно. Он работает с версией моментального снимка. Спасибо! - person Francesco Papagno; 24.02.2016

В какой-то момент вы анализируете json, я подозреваю, что он читается из файла.

Похоже, этот файл сохранен в неправильной кодировке, например, ISO-8859-1. Убедитесь, что он сохранен в кодировке UTF-8, UTF-16 или UTF-32. Большинство парсеров JSON угадывают кодировку по первым четырем байтам и терпят неудачу, если находят неподдерживаемую кодировку.

person f1sh    schedule 24.02.2016
comment
Данные берутся из базы данных MySQL. Чего я не понимаю, так это разницы между maven и IDE. - person Francesco Papagno; 24.02.2016
comment
IDE, вероятно, использует UTF-8, в то время как maven при запуске в командной строке использует кодировку платформы (которая по-прежнему является ISO-8859-1 или Latin1 на компьютерах с Windows). Попробуйте добавить -Dfile.encoding="UTF-8" в свой оператор командной строки и посмотрите, изменит ли это что-нибудь. - person f1sh; 24.02.2016
comment
Ничего не изменилось, и у меня уже был <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> в моем pom. - person Francesco Papagno; 24.02.2016
comment
Проблема заключается в чтении из базы данных. Вариант, который я предложил, и ваши настройки в pom.xml не влияют на содержимое базы данных... Можете ли вы опубликовать код, который участвует в чтении json из базы данных? - person f1sh; 24.02.2016
comment
Я использую Spring Data и Spring MVC, поэтому Джексон сериализует модели в JSON. (Я отредактировал вопрос, потому что, если я удалю код spring-restdoc, тест пройдет с maven.) - person Francesco Papagno; 24.02.2016