且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何使用 objectMapper 为 java.time.Instant 设置字符串格式?

更新时间:2023-09-18 16:36:34

一种解决方案是使用 jackson-modules-java8.然后你可以添加一个 JavaTimeModule 到你的对象映射器:

One solution is to use jackson-modules-java8. Then you can add a JavaTimeModule to your object mapper:

ObjectMapper objectMapper = new ObjectMapper();

JavaTimeModule module = new JavaTimeModule();
objectMapper.registerModule(module);

默认情况下,Instant 被序列化为纪元值(单个数字中的秒和纳秒):

By default the Instant is serialized as the epoch value (seconds and nanoseconds in a single number):

{"createdDate":1502713067.720000000}

您可以通过在对象映射器中进行设置来更改它:

You can change that by setting in the object mapper:

objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

这将产生输出:

{"createdDate":"2017-08-14T12:17:47.720Z"}

以上两种格式均已反序列化,无需任何额外配置.

Both formats above are deserialized without any additional configuration.

要更改序列化格式,只需在字段中添加一个JsonFormat注解:

To change the serialization format, just add a JsonFormat annotation to the field:

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "UTC")
private Instant createdDate;

需要设置时区,否则Instant无法正确序列化(抛出异常).输出将是:

You need to set the timezone, otherwise the Instant can't be serialized properly (it throws an exception). The output will be:

{"createdDate":"2017-08-14 12:17:47"}

如果您不想(或不能)使用 java8 模块,另一种选择是使用 java.time.format.DateTimeFormatter 创建自定义序列化器和反序列化器:


Another alternative, if you don't want to (or can't) use java8 modules, is to create a custom serializer and deserializer, using a java.time.format.DateTimeFormatter:

public class MyCustomSerializer extends JsonSerializer<Instant> {

    private DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneOffset.UTC);

    @Override
    public void serialize(Instant value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
        String str = fmt.format(value);

        gen.writeString(str);
    }
}

public class MyCustomDeserializer extends JsonDeserializer<Instant> {

    private DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneOffset.UTC);

    @Override
    public Instant deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        return Instant.from(fmt.parse(p.getText()));
    }
}

然后您使用这些自定义类来注释该字段:

Then you annotate the field with those custom classes:

@JsonDeserialize(using = MyCustomDeserializer.class)
@JsonSerialize(using = MyCustomSerializer.class)
private Instant createdDate;

输出将是:

{"createdDate":"2017-08-14 12:17:47"}

一个细节是,在序列化字符串中,您丢弃了秒的小数部分(小数点后的所有内容).因此,在反序列化时,此信息无法恢复(将设置为零).


One detail is that in the serialized string you're discarding the fraction of second (everything after the decimal point). So, when deserializing, this information can't be recovered (it'll be set to zero).

上例中,原Instant2017-08-14T12:17:47.720Z,但序列化后的字符串为2017-08-1412:17:47(没有秒的分数),所以当反序列化时,结果 Instant2017-08-14T12:17:47Z(.720 毫秒丢失).

In the example above, the original Instant is 2017-08-14T12:17:47.720Z, but the serialized string is 2017-08-14 12:17:47 (without the fraction of seconds), so when deserialized the resulting Instant is 2017-08-14T12:17:47Z (the .720 milliseconds are lost).