【问题标题】:Jackson deserialization issue for ZonedDateTimeZonedDateTime 的杰克逊反序列化问题
【发布时间】:2016-04-18 06:56:58
【问题描述】:

我在反序列化正在使用的服务期间使用的类中有以下字段。

private ZonedDateTime transactionDateTime;

我正在使用的服务可能会使用以下模式返回 Date 或 DateTime:yyyy-MM-dd'T'HH:mm:ss.SSSZ

让我举两个服务返回的例子:

  • 2015-11-18T18:05:38.000+0200
  • 2015-11-18T00:00:00.000+0200

虽然第一个运行良好,但后者在反序列化过程中会引发以下异常:

java.time.format.DateTimeParseException:文本 '2015-11-18T00:00:00.000+0200' 无法在索引 23 处解析

我正在使用;

  • Spring Boot 1.3.1
  • Jackson 2.6.4(包含 JSR310 模块)

这是否需要自定义反序列化类?

【问题讨论】:

    标签: java json spring jackson jsr310


    【解决方案1】:

    您可以使用如下注释:

    @JsonSerialize(using = MyCustomJsonDateSerializer.class)
    

    @JsonDeserialize(using = MyCustomJsonDateDeserializer.class)
    

    自定义 Jackson 解析日期的方式。那些自定义的 Serializer 和 Deserializer 必须扩展 JsonSerializer 和 JsonDeserializer。例如:

    public class MyCustomJsonDateSerializer extends JsonSerializer<Date> {
    
        @Override
        public void serialize(Date date, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
            jgen.writeString(date != null ? ISODateTimeFormat.dateTime().print(new DateTime(date)) : null);
          }
    }
    

    【讨论】:

      【解决方案2】:

      在代码的早期,我使用带有 @JsonFormat 注释的字段,但删除了它,因为我认为它只是像 JavaDocs 建议的那样用于序列化。

      原来我需要重新添加该注释。真正的问题是第 3 方服务响应确实是错误的(它在 XML 中缺少包装元素),导致反序列化失败。错误是:

      com.fasterxml.jackson.databind.JsonMappingException: 不能 实例化类型的值 [简单类型,类 com.foo.bar.adapter.john.model.account.UserAccount] 来自字符串值('2015-11-18T00:00:00.000+0200');没有单串 构造函数/工厂方法

      字段的写法如下:

      @JsonFormat(pattern = Constants.DATETIME_FORMAT)
      @JacksonXmlProperty(localName = "transactionDate")
      private ZonedDateTime transactionDateTime;
      

      我还必须将@JsonRootName("transaction") 添加到该字段的类中,因为该对象被包装到一个集合中。

      【讨论】:

      • 你能分享一下模式吗? Constants.DATETIME_FORMAT
      • yyyy-MM-dd'T'HH:mm:ss.SSSZ
      • 谢谢,但这对我不起作用,最终我通过为 ZonedDateTime 类编写自定义序列化器和反序列化器解决了我的问题。
      • 你的类路径有 JSR310 依赖吗?
      • 是的,我使用 ZonedDatetime。序列化工作正常,但反序列化结束 UTC zonedDateTime 对象
      【解决方案3】:

      Jackson 反序列化将默认绕过时区信息并使用 ctx 时区覆盖它,所有 ISO8601 都会以 UTC 结束

      如果你在春天,这个功能可以被关闭

      spring.jackson.deserialization.ADJUST_DATES_TO_CONTEXT_TIME_ZONE=false
      

      【讨论】:

      • 或者如果使用杰克逊映射器new ObjectMapper().registerModule(new JavaTimeModule()).disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)
      【解决方案4】:

      我用过

      @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ssXXX")
      private ZonedDateTime startDate;
      

      加上jackson-datatype-jsr310 库,很明显。

      Jackson deserialize ISO8601 formatted date-time into Java8 Instant中描述了这个解决方案

      【讨论】:

        【解决方案5】:

        以下配置对我有帮助

        指定日期时间模式:

        public class Timestamp {
        
            @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ssXXX")
            private ZonedDateTime timestamp;
        
        }
        

        禁用将 ZonedDateTime 转换为 UTC:

        objectMapper.configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, false);
        

        还有另一个问题,可能很难发现。就我而言,我使用 RestTemplate 从另一个微服务接收Timestamp。 RestTemplate 可以配置为使用 notProjectDefaultObjectMapper,它不受默认 Spring Jackson 配置方法的影响(如应用程序属性,或带有 Jackson2ObjectMapperBuilderCustomizer bean 定义的 @Configuration 类或其他方式)。所以RestTemplate的objectMapper(如果有的话)也要配置

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-12-18
          • 1970-01-01
          • 2022-12-12
          • 2020-12-24
          • 2015-04-07
          • 1970-01-01
          • 2012-11-19
          相关资源
          最近更新 更多