jackson Java 8 Time API的ObjectMapper配置

fhity93d  于 4个月前  发布在  Java
关注(0)|答案(4)|浏览(70)

我们正在从Joda迁移到Java Time。目前我们在实体中使用Joda的DateTime。AFAIK DateTime相当于Java中的两种类型:OffsetDateTimeZonedDateTime。由于我们要将它们持久化到DB中,因此我们将使用OffsetDateTime(对此有何评论?)
现在的问题是如何正确配置Jackson的ObjectMapper。我在网上找到的所有示例都是关于Jackson已经提供的反序列化器实现的本地类型(例如LocalDateTimeLocalDateTimeSerializerLocalDateTimeDeserializer)。
我终于做到了这样一件事:

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));
    }

}

字符串

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);
    }

}


现在我的问题是,配置Jackson的ObjectMapper来反序列化Java 8日期-时间值的最佳方法是什么?
最新消息:公认的答案并不能真正解决我的问题(请阅读评论中的讨论)。我最终得到了比我在上面提出的代码简单一点的代码。也请参阅我自己的答案。

ufj5ltwl

ufj5ltwl1#

您不需要为JSR-310类型编写自定义的序列化器和反序列化器。Jackson有一个自定义模块来处理这一问题,并将为您提供所需的serializerdeserializer
首先将jackson-datatype-jsr310工件添加到依赖项中:

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.9</version>
</dependency>

字符串
然后在ObjectMapper中注册JavaTimeModule模块:

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);


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

nwsw7zdq

nwsw7zdq2#

好了,我最后得到了以下代码(代码少了一点,没有具体的类):

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) {};
}

字符串

nqwrtyyt

nqwrtyyt3#

你可以检查这个答案,它包含了很多关于如何使用java.time类和自定义格式的信息:https://stackoverflow.com/a/46263957
要解析“+00:00”和“+0000”,您可以使用带有可选部分的DateTimeFormatterBuilder

DateTimeFormatter f = new DateTimeFormatterBuilder()
    // date and time fields
    .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
    // optional offset in format hh:mm
    .optionalStart()
    .appendOffset("+HH:MM", "+00:00")
    .optionalEnd()
    // optional offset in format hhmm
    .optionalStart()
    .appendOffset("+HHMM", "+0000")
    .optionalEnd()
    .toFormatter();

字符串

zc0qhyus

zc0qhyus4#

Sping Boot 为Jackson做了依赖管理,在2.6之后,jsr 310模块可以自动管理,所以你只需要使用Jackson2.6+,模块就被添加了,在com.fasterxml.jackson.datatype:jackson-datatype-jsr310中可用。
如果你可以访问ObjectMapper,比如在单元测试中,你可以注册JavaTimeModule。如果你没有,比如JSON作为@RequestBody出现时,你必须在application.properties中配置:

spring.jackson.serialization.write-dates-as-timestamps=false

字符串
并在JSON中指定日期格式,如:

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ssXXXX")
private OffsetDateTime transactionDateTime;


并且字符串将被正确解析。格式使用SimpleDateFormat中指定的字母。
注意结尾处X的数量;不同长度的X表示不同形式的区域偏移。阅读Java API SimpleDateFormat部分以获取更多信息。

相关问题