将毫秒级时间戳反序列化为java.time.Instant

Mar*_*unt 7 java serialization jackson deserialization java-time

我正在尝试使用Jackson读取JSON文件,并以Java的纪元毫秒形式存储其中一个字段Instant,但是反序列化的行为不符合预期。

这是我尝试读取时间戳时看到的内容:

1503115200000

杰克逊将Instant领域设置为+49601-10-28T16:00:00Z

发生这种情况是因为Jackson的默认设置是使用Instant.ofEpochSecond(Long l)而不是读取时间戳Instant.ofEpochMilli(Long l)

有没有一种方法可以将Jackson设置ObjectMapper为使用该ofEpochMilli方法呢?这是我目前拥有的ObjectMapper

ObjectMapper om = new ObjectMapper()
            .registerModule(new JavaTimeModule())
            .configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false)
            .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
            .setSerializationInclusion(Include.NON_NULL);
Run Code Online (Sandbox Code Playgroud)

注意

如果我将输入JSON更改为ISO日期(例如)2017-08-19T04:00:00Z或epoch seconds(例如纪元秒),1503115200Instant字段可以正确设置。

不幸的是JSON输入必须是纪元毫秒,例如1503115200000

小智 14

对于那些使用Spring Boot并在 rest 请求反序列化期间遇到此问题的人 - 在 application.properties 中提供:

spring.jackson.deserialization.read-date-timestamps-as-nanoseconds=false

@JB Nizet 答案是正确的,但由于 Spring Boot 内部有自己的 ObjectMapper - 您需要在属性中配置此值。


bil*_*zez 7

如果您不想编辑或创建对象映射器,更灵活的解决方案可能是编写自己的转换器类。

public class LongToInstantConverter extends StdConverter<Long, Instant> {
    public Instant convert(final Long value) {
        return Instant.ofEpochMilli(value);
    }
}
Run Code Online (Sandbox Code Playgroud)

您只需要在您的类中添加注释即可

@JsonDeserialize(converter = LongToInstantConverter.class)
private Instant sentDate;
Run Code Online (Sandbox Code Playgroud)


Mar*_*unt 5

解决方案是将其添加.configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, false)到ObjectMapper。完整的ObjectMapper看起来像:

ObjectMapper om = new ObjectMapper()
            .registerModule(new JavaTimeModule())
            .configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false)
            .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
            .configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, false)
            .setSerializationInclusion(Include.NON_NULL);
Run Code Online (Sandbox Code Playgroud)


JB *_*zet 5

来自https://github.com/FasterXML/jackson-modules-java8/blob/master/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/JavaTimeModule.java

如果启用了{@code READ_DATE_TIMESTAMPS_AS_NANOSECONDS}(默认情况下),则更模糊的整数类型将读取为不带小数点的小数秒,否则它们将读取为毫秒。

因此,您需要禁用 READ_DATE_TIMESTAMPS_AS_NANOSECONDS。