Jackson - 无法使用时区偏移反序列化日期时间 'unparsed text found at index 23'

Jackson - Can't deserialize datetime with timezone offset 'unparsed text found at index 23'

我的日期时间必须来自具有时区偏移的前端:2017-07-04T06:00:00.000+01:00

我无法用 Jackson 反序列化它。 错误是:

Text '2017-07-04T06:00:00.000+01:00' could not be parsed, unparsed text found at index 23;

我试图 Google 所有人的解决方案都是关于 DateTime 和 Z 在最后。

    @NotNull
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS aZ")
    private LocalDateTime time;

有解决办法吗?

pattern a is used to parse AM/PM,它不在输入 String 中,这就是你得到解析错误的原因。

输入格式匹配一个OffsetDateTime,可以用相应的built-in formatter DateTimeFormatter.ISO_OFFSET_DATE_TIME解析,所以你可以在反序列化器对象中使用这个格式化程序并在模块中注册它。您还必须从字段中删除 JsonFormat 注释。

ObjectMapper om = new ObjectMapper();
JavaTimeModule module = new JavaTimeModule();
LocalDateTimeDeserializer deserializer = new LocalDateTimeDeserializer(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
module.addDeserializer(LocalDateTime.class, deserializer);
om.registerModule(module);

这将解析输入并将其转换为 LocalDateTime。在我所做的测试中, LocalDateTime 的值被设置为 2017-07-04T06:00.


要控制输出,您可以这样做:

om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

这会将 LocalDateTime 输出为 2017-07-04T06:00:00,或者您可以使用自定义格式化程序:

LocalDateTimeSerializer serializer = new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS a"));
module.addSerializer(LocalDateTime.class, serializer);

上面的序列化程序会将字段输出为 2017-07-04T06:00:00.000 AM。请注意 Z 模式将不起作用,因为 LocalDateTime 没有时区信息并且无法解析其偏移量 - 因为当您反序列化为 LocalDateTime 时,偏移量信息在输入 (+01:00) 丢失。


另一种选择(无需配置对象映射器)是在注释中使用正确的模式:

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS[xxx]")
private LocalDateTime time;

请注意,我使用了模式 [xxx],因为偏移量 (+01:00) 可以是可选的:反序列化时,此信息会丢失,因为 LocalDateTime 没有关于时区的信息,并且偏移量,因此在序列化时找不到该字段 - 使该字段可选(使用 [] 定界符)使其适用于反序列化和序列化。

这将反序列化输入 2017-07-04T06:00:00.000+01:00 并序列化为 2017-07-04T06:00:00.000(请注意,序列化中不使用可选偏移量,因为 LocalDateTime 没有此类信息)。


如果你想要反序列化和序列化的不同格式,你也可以创建自定义 类 并在字段中注释它们:

public class CustomDeserializer extends LocalDateTimeDeserializer {
    public CustomDeserializer() {
        super(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
    }
}

public class CustomSerializer extends LocalDateTimeSerializer {
    public CustomSerializer() {
        super(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS a"));
    }
}

// in this case, don't use @JsonFormat
@JsonSerialize(using = CustomSerializer.class)
@JsonDeserialize(using = CustomDeserializer.class)
private LocalDateTime time;

这将使用格式 2017-07-04T06:00:00.000+01:00 进行反序列化,使用格式 2017-07-04T06:00:00.000 AM 进行序列化。