Java 8 Time API 的 ObjectMapper 配置

问题描述 投票:0回答:4

我们正在从 Joda 迁移到 Java 时间。目前我们在实体中使用 Joda 的

DateTime
。 AFAIK
DateTime
相当于 Java 中的两种类型:
OffsetDateTime
ZonedDateTime
。由于我们要将它们持久保存在数据库中,因此我们将使用
OffsetDateTime
(对此有何评论?)。

现在的问题是如何正确配置Jackson的

ObjectMapper
。 我在网上找到的所有示例都是关于杰克逊已经提供的反/序列化器实现的本地类型(例如
LocalDateTime
LocalDateTimeSerializer
LocalDateTimeDeserializer
)。

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

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 日期时间值的最佳方法是什么?

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

java jackson java-time jackson-databind jackson-modules
4个回答
18
投票

您不需要为 JSR-310 类型编写自定义序列化器和反序列化器。 Jackson 有一个自定义模块来处理这个问题,并将为您提供所需的 serializerdeserializer

首先将

jackson-datatype-jsr310
工件添加到您的依赖项中:

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

然后在您的

JavaTimeModule
中注册
ObjectMapper
模块:

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

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

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


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

1
投票

您可以查看此答案,其中包含有关如何使用 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();

0
投票

Spring boot 为 Jackson 进行依赖管理。在2.6上,jsr310模块可以自动管理,所以你只需使用Jackson 2.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
的数量;其不同的长度代表不同形式的区域偏移。阅读 Java API
SimpleDateFormat
部分以获取更多信息。

© www.soinside.com 2019 - 2024. All rights reserved.