如何使用objectMapper設定java.time.Instant的字串格式?

二十一克陽光!發表於2020-09-25
  1. 我有一個帶有 java.time.Instant的實體用於建立的資料欄位:
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class Item {
    private String id;
    private String url;
    private Instant createdDate;
}

我使用com.fasterxml.jackson.databind.ObjectMapper將專案儲存為JSON格式,ObjectMapper將此欄位序列化為物件:

"createdDate": {
    "epochSecond": 1502643595,
    "nano": 466000000
}

一種解決方案是使用 jackson-modules-java8.然後您可以將JavaTimeModule新增到物件對映器:

ObjectMapper objectMapper = new ObjectMapper();

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

預設情況下,Instant被序列化為紀元值(單個數字中的秒和納秒):

{"createdDate":1502713067.720000000}

您可以通過在物件對映器中設定來更改它:

objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

這將產生輸出:

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

上述兩種格式都是反序列化的,無需任何其他配置.

要更改序列化格式,只需在欄位中新增JsonFormat註釋:

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

您需要設定時區,否則Instant無法正確序列化(它會引發異常).輸出將是:

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

如果您不想(或不能)使用java8模組,另一種方法是使用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()));
    }
}

然後使用這些自定義類註釋該欄位:

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

輸出將是:

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

一個細節是,在序列化字串中,您將丟棄秒的小數部分(小數點後的所有內容).因此,在反序列化時,此資訊無法恢復(它將被設定為零).
在上面的例子中,原始的Instant是2017-08-14T12:17:47.720Z,但是序列化的字串是2017-08-14 12:17:47(沒有秒的分數),所以當反序列化時產生的Instant是2017-08-14T12:17:47Z(丟失.720毫秒).

相關文章