ZonedDateTime的杰克逊反序列化问题

tun*_*nix 7 java spring json jackson jsr310

我在我正在使用的服务的反序列化过程中使用的类中有以下字段.

private ZonedDateTime transactionDateTime;
Run Code Online (Sandbox Code Playgroud)

我正在使用的服务可能会使用以下模式返回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:无法在索引23处解析文本'2015-11-18T00:00:00.000 + 0200'

我正在使用;

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

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

小智 8

Jackson 反序列化器默认会绕过时区信息并使用上下文时区来覆盖它,所有 ISO8601 都会以 UTC 结束。

使用 Spring,可以通过以下方式关闭此功能:

spring.jackson.deserialization.ADJUST_DATES_TO_CONTEXT_TIME_ZONE=false
Run Code Online (Sandbox Code Playgroud)


Ric*_*ila 5

您可以使用以下注释:

@JsonSerialize(using = MyCustomJsonDateSerializer.class)
Run Code Online (Sandbox Code Playgroud)

或者

@JsonDeserialize(using = MyCustomJsonDateDeserializer.class)
Run Code Online (Sandbox Code Playgroud)

自定义 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);
      }
}
Run Code Online (Sandbox Code Playgroud)


tun*_*nix 4

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

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

com.fasterxml.jackson.databind.JsonMappingException:无法从字符串值('2015-11-18T00:00: 00.000+0200'); 没有单字符串构造函数/工厂方法

该字段的写法如下:

@JsonFormat(pattern = Constants.DATETIME_FORMAT)
@JacksonXmlProperty(localName = "transactionDate")
private ZonedDateTime transactionDateTime;
Run Code Online (Sandbox Code Playgroud)

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

  • yyyy-MM-dd'T'HH:mm:ss.SSSZ (2认同)