InvalidFormatException for Date - исправление без использования JsonFormat или изменения исходного класса - PullRequest
0 голосов
/ 16 октября 2019

Введение

Мы используем пользовательский стартер, размещенный в репозитории nexus, который содержит симулированные клиенты cloud-cloud, которые отправляют запросы на микросервисы.

Один из микросервисов возвращает даты как «дд-мм-гггг ЧЧ: мм: ссЗ», и это работает в большинстве наших приложений. Однако у нас есть одно приложение, которое выдает следующую ошибку:

Caused by: com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `java.util.Date` from String "2019-10-16 14:23:17": not a valid representation (error: Failed to parse Date value '2019-10-16 14:23:17': Unparseable date: "2019-10-16 14:23:1
7")

Текущий обходной путь

Мой Текущий обход, так как я не хочу загрязнять стартер,расширить класс и создать локальный feign-client и локальный pojo с соответствующим JsonFormat:

public class DocumentMetaDataFix extends DocumentMetaData {
    @JsonFormat(
        shape = Shape.STRING,
        pattern = "yyyy-MM-dd HH:mm:ss"
    )
    private Date creationDate;
    @JsonFormat(
        shape = Shape.STRING,
        pattern = "yyyy-MM-dd HH:mm:ss"
    )

Failed Fixes

Я попробовал следующее в своем классе конфигурации, чтобы попробоватьвлияет на десериализацию с другого пути. Однако DocumentMetaDataSerializer никогда не вызывается. Бин ObjectMapper IS называется.

  @Configuration
    @EnableSpringDataWebSupport
    @RequiredArgsConstructor
    public class MyConfig extends WebMvcConfigurerAdapter {

   @Bean
    public Jackson2ObjectMapperBuilderCustomizer addCustomBigDecimalDeserialization() {
        return new Jackson2ObjectMapperBuilderCustomizer() {

            @Override
            public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
                jacksonObjectMapperBuilder.deserializerByType(DocumentMetaData.class, new DocumentMetaDataDeserializer());
            }

        };
    }


    @Primary
    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true);
        mapper.setDateFormat(new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"));
        //mapper.configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, true);
        return mapper;
    }

    @Bean
    public Module dynamoDemoEntityDeserializer() {
        SimpleModule module = new SimpleModule();
        module.addDeserializer(DocumentMetaData.class, new DocumentMetaDataDeserializer());
        return module;
    }

    public static class DocumentMetaDataDeserializer extends JsonDeserializer<DocumentMetaData> {
        @Override
        public DocumentMetaData deserialize(JsonParser jp, DeserializationContext ctxt)
                throws IOException, JsonProcessingException {
            // return DynamoDemoEntity instance;

            JsonNode node = jp.getCodec().readTree(jp);


            return null;
        }

        public DocumentMetaData deserializeWithType(JsonParser jp, DeserializationContext ctxt, TypeDeserializer t) throws IOException {
            JsonNode node = jp.getCodec().readTree(jp);


            return null;
        }

    }

Full Stacktrace

Caused by: com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `java.util.Date` from String "2019-10-16 14:23:17": not a valid representation (error: Failed to parse Date value '2019-10-16 14:23:17': Unparseable date: "2019-10-16 14:23:1
7")
 at [Source: (ByteArrayInputStream); line: 1, column: 580] (through reference chain: eu.europa.ec.nova.documentstore.DocumentMetaData["creationDate"])
        at com.fasterxml.jackson.databind.exc.InvalidFormatException.from(InvalidFormatException.java:67)
        at com.fasterxml.jackson.databind.DeserializationContext.weirdStringException(DeserializationContext.java:1548)
        at com.fasterxml.jackson.databind.DeserializationContext.handleWeirdStringValue(DeserializationContext.java:910)
        at com.fasterxml.jackson.databind.deser.std.StdDeserializer._parseDate(StdDeserializer.java:524)
        at com.fasterxml.jackson.databind.deser.std.StdDeserializer._parseDate(StdDeserializer.java:467)
        at com.fasterxml.jackson.databind.deser.std.DateDeserializers$DateBasedDeserializer._parseDate(DateDeserializers.java:195)
        at com.fasterxml.jackson.databind.deser.std.DateDeserializers$DateDeserializer.deserialize(DateDeserializers.java:285)
        at com.fasterxml.jackson.databind.deser.std.DateDeserializers$DateDeserializer.deserialize(DateDeserializers.java:268)
        at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:127)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:288)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
        at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4013)
        at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3084)
        at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:237)
        ... 70 common frames omitted

Итак, есть какие-нибудь идеи? Я искал в проекте ссылки на Джексона, если естьчто-нибудь еще в моем проекте, вызывающее это.

Я попытаюсь зайти внутрь ObjectMapper и попытаться отладить текущие параметры / поля конфигурации в ObjectMapper.java:3084 из стека:1026 *

at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3084)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:237)
... 67 common frames omitted

Обновление

Я добавил точку останова в конструкторе объектного преобразователя и вижу, что она инициализируется из нескольких мест. Это заставило меня заподозрить, что spring-boot не использует мой ObjectMapper. Вместо этого он использует внутреннюю пружину, которая вызывается из MappingJackson2HttpMessageConverter.

<init>:480, ObjectMapper
build:606, Jackson2ObjectMapperBuilder
<init>:59, MappingJackson2HttpMessageConverter
<init>:74, AllEncompassingFormHttpMessageConverter

Поэтому я попытаюсь переопределить эту внутреннюю пружину, основываясь на результатах, которые я нашел: Как настроить отображение JSON Джексона, неявно используемое Spring Boot?

Однако это также не удалось.

Ссылки

  1. Можно ли настроить пользовательские десериализаторы Jackson на уровне класса для разных типов данных?
  2. https://docs.spring.io/spring-boot/docs/current/reference/html/howto-spring-mvc.html#howto-customize-the-jackson-objectmapper
  3. https://www.baeldung.com/jackson-deserialization
  4. очень полезно: https://mostafa -asg.github.io / post/ customize-json-xml-spring-mvc-output /
  5. Как настроить Джексона в Spring Boot 1.4

Обновление - окончательный списокпытается

По-прежнему происходит сбой с ошибкой.

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
    builder.serializationInclusion(JsonInclude.Include.NON_NULL);
    builder.propertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
    builder.serializationInclusion(Include.NON_EMPTY);
    builder.indentOutput(true).dateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
    converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
    converters.add(new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build()));

    //converters.add(cmsaMessageConverter());
    converters.add(new StringHttpMessageConverter());
    converters.add(new FormHttpMessageConverter());
    converters.add(new MappingJackson2HttpMessageConverter());
}


@Bean
public Jackson2ObjectMapperBuilderCustomizer addCustomBigDecimalDeserialization() {
    return new Jackson2ObjectMapperBuilderCustomizer() {

        @Override
        public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
            jacksonObjectMapperBuilder.deserializerByType(DocumentMetaData.class, new DocumentMetaDataDeserializer());
        }

    };
}


@Primary
@Bean
public ObjectMapper objectMapper() {
    ObjectMapper mapper = new ObjectMapper();
    mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true);
    mapper.setDateFormat(new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"));
    //mapper.configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, true);
    return mapper;
}

@Bean
public Module dynamoDemoEntityDeserializer() {
    SimpleModule module = new SimpleModule();
    module.addDeserializer(DocumentMetaData.class, new DocumentMetaDataDeserializer());
    return module;
}

public static class DocumentMetaDataDeserializer extends JsonDeserializer<DocumentMetaData> {
    @Override
    public DocumentMetaData deserialize(JsonParser jp, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {
        // return DynamoDemoEntity instance;

        JsonNode node = jp.getCodec().readTree(jp);


        return null;
    }

    public DocumentMetaData deserializeWithType(JsonParser jp, DeserializationContext ctxt, TypeDeserializer t) throws IOException {
        JsonNode node = jp.getCodec().readTree(jp);


        return null;
    }

}

По-прежнему происходит сбой с ошибкой.

1 Ответ

0 голосов
/ 16 октября 2019

Попробуйте использовать LocalDateTime, это то, что я делаю и работаю для меня

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime date;
...