Java 8 Time API的ObjectMapper配置

Rad*_*Rad 4 java jackson jackson-modules java-time jackson-databind

我们正在从Joda迁移到Java Time.目前我们DateTime在我们的实体中使用Joda.AFAIK DateTime相当于Java中的两种类型:OffsetDateTimeZonedDateTime.既然我们要将它们保存在数据库中,我们将使用OffsetDateTime(对此有何评论?).

现在的问题是如何ObjectMapper正确配置杰克逊.我在网上找到的所有例子都是关于Jackson已经提供de/serializer实现的本地类型(例如LocalDateTime,LocalDateTimeSerializerLocalDateTimeDeserializer).

我终于设法做了这样的事情:

public class OffsetDateTimeSerializer extends StdSerializer<OffsetDateTime> {

    private final DateTimeFormatter formatter; // We need custom format!

    public OffsetDateTimeSerializer(DateTimeFormatter formatter) {
        super(OffsetDateTime.class);
        this.formatter = formatter;
    }

    @Override
    public void serialize(OffsetDateTime value, JsonGenerator generator, SerializerProvider provider) throws IOException {
        generator.writeString(value.format(formatter));
    }

}
Run Code Online (Sandbox Code Playgroud)

public class OffsetDateTimeDeserializer extends StdDeserializer<OffsetDateTime> {

    private final DateTimeFormatter formatter; // We need custom format!

    public OffsetDateTimeDeserializer(DateTimeFormatter formatter) {
        super(OffsetDateTime.class);
        this.formatter = formatter;
    }

    @Override
    public OffsetDateTime deserialize(JsonParser parser, DeserializationContext ctx) throws IOException {
        return OffsetDateTime.parse(parser.readValueAs(String.class), formatter);
    }

}
Run Code Online (Sandbox Code Playgroud)

现在我的问题是配置Jackson的ObjectMapperde/serialize Java 8日期时间值的最佳方法是什么?

更新:接受的答案并没有真正解决我的问题(阅读评论中的讨论).我最终得到的代码比我上面提到的更简单.看看我自己的答案.

cas*_*lin 11

您不需要为JSR-310类型编写自定义序列化程序和反序列化程序.杰克逊有一个自定义模块来处理,并会为您提供串行解串器需要.

首先将jackson-datatype-jsr310工件添加到依赖项:

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.9</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

然后JavaTimeModule在您的注册模块ObjectMapper:

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
Run Code Online (Sandbox Code Playgroud)

大多数JSR-310类型将使用标准ISO-8601字符串表示进行序列化.如果需要自定义格式,可以使用自己的序列化器和反序列化器实现.

有关详细信息,请参阅文档

  • 注意ISO-8601的微秒部分.在序列化恰好为0.000的Instants时,我们遇到了时间戳缺少.SSS部分的问题.如果这对您的客户来说是个问题,那么您需要自定义序列化以使用不执行此操作的自定义模式:"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'". (2认同)

Rad*_*Rad 7

好的,所以我最终得到了以下内容(代码少了一些,没有具体的类):

private JavaTimeModule newJavaTimeModule() {
    JavaTimeModule module = new JavaTimeModule();
    module.addSerializer(LocalDate.class, new LocalDateSerializer(DEFAULT_LOCAL_DATE_FORMATTER));
    module.addDeserializer(LocalDate.class, new LocalDateDeserializer(DEFAULT_LOCAL_DATE_FORMATTER));
    module.addSerializer(OffsetDateTime.class, offsetDateTimeSerializer(DEFAULT_DATE_TIME_FORMATTER));
    module.addDeserializer(OffsetDateTime.class, offsetDateTimeDeserializer(DEFAULT_DATE_TIME_FORMATTER));

    return module;
}

private StdSerializer<OffsetDateTime> offsetDateTimeSerializer(DateTimeFormatter formatter) {
    return new OffsetDateTimeSerializer(OffsetDateTimeSerializer.INSTANCE, false, formatter) {};
}

private StdDeserializer<OffsetDateTime> offsetDateTimeDeserializer(DateTimeFormatter formatter) {
    return new InstantDeserializer<OffsetDateTime>(InstantDeserializer.OFFSET_DATE_TIME, formatter) {};
}
Run Code Online (Sandbox Code Playgroud)