InvalidFormatException for Date - 在不使用 JsonFormat 或修改原始类的情况下进行修复

Posted

技术标签:

【中文标题】InvalidFormatException for Date - 在不使用 JsonFormat 或修改原始类的情况下进行修复【英文标题】:InvalidFormatException for Date - fixing without using JsonFormat or modifying original class 【发布时间】:2020-02-13 05:52:26 【问题描述】:

简介

我们正在使用一个托管在 nexus 存储库上的自定义启动器,其中包含向微服务发出请求的 spring-cloud-feign 客户端。

其中一个微服务将日期返回为“dd-MM-yyyy HH:mm:ssZ”,这适用于我们的大多数应用程序。但是,我们有一个应用程序抛出以下错误:

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")

当前的解决方法

由于我不想污染启动器,我当前的解决方法是扩展类并使用正确的 JsonFormat 创建本地 feign-client 和本地 pojo:

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"
    )

修复失败

我在我的配置类中尝试了以下操作,以尝试从另一个路径影响反序列化。但是,永远不会调用 DocumentMetaDataSerializer。调用 ObjectMapper bean。

  @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;
        

    

完整的堆栈跟踪

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

那么,有什么想法吗? 我已经在项目中搜索了对 Jackson 的引用,以防我的项目中还有其他原因导致此问题。

我将尝试进入 ObjectMapper 并尝试从堆栈中调试 ObjectMapper.java:3084 中配置的当前参数/字段:

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

更新

我在 objectmapper 构造函数中添加了一个断点,并且看到它正在从多个位置初始化。这让我怀疑 spring-boot 没有使用我的 ObjectMapper。相反,它使用的是从 MappingJackson2HttpMessageConverter 调用的内部弹簧。

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

因此,我将根据我从以下网址找到的结果尝试覆盖这个内部弹簧:How to customise the Jackson JSON mapper implicitly used by Spring Boot?

但这也失败了。

参考文献

    Is it possible to configure Jackson custom deserializers at class level for different data types? https://docs.spring.io/spring-boot/docs/current/reference/html/howto-spring-mvc.html#howto-customize-the-jackson-objectmapper https://www.baeldung.com/jackson-deserialization 非常有用: https://mostafa-asg.github.io/post/customize-json-xml-spring-mvc-output/ How to customise Jackson in 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】:

尝试使用 LocalDateTime, 这就是我正在做的和为我工作的事情

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

【讨论】:

以上是关于InvalidFormatException for Date - 在不使用 JsonFormat 或修改原始类的情况下进行修复的主要内容,如果未能解决你的问题,请参考以下文章

vbscript InvalidFormatException.vb

vbscript InvalidFormatException.vb

如何处理枚举中空值的 InvalidFormatException

InvalidFormatException:Your stream was neither an OLE2 stream, nor an OOXML stream

InvalidFormatException for Date - 在不使用 JsonFormat 或修改原始类的情况下进行修复

java 读取excel