通過Jackson的String轉joda.DateTime的採坑記錄

希-望圓滿-
背景:最近公司在做秒殺活動,剛好我做的活動時間處理那塊;其中一塊是負責把前臺的json通過Jackson轉爲joda.DateTime,但是就在這中間出現了問題

問題描述

直接把"2019-10-24 00:00:00"通過Jackson轉爲DateTime時,會產生如下錯誤:

org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `org.joda.time.DateTime` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('2019-10-24 00:00:00'); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `org.joda.time.DateTime` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('2019-10-24 00:00:00')
 at ...
Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `org.joda.time.DateTime` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('2019-10-24 00:00:00')
 at ...

感覺是構造器出了問題,導入了jackson-core,jackson-databind ,jackson-datatype-joda三個包後,同時,又在application.properties中配置了time-format:spring.jackson.joda-date-time-format="yyyy-MM-dd HH:mm:ss"後,重新運行,發現仍然有問題:

org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Invalid format: "2019-10-24 00:00:00" is malformed at " 00:00:00"; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Invalid format: "2019-10-24 00:00:00" is malformed at " 00:00:00" (through reference chain: com.savannah.service.model.PromoDTO["startDate"])
	at ...
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Invalid format: "2019-10-24 00:00:00" is malformed at " 00:00:00" (through reference chain: com.savannah.service.model.PromoDTO["startDate"])
	at ...
Caused by: java.lang.IllegalArgumentException: Invalid format: "2019-10-24 00:00:00" is malformed at " 00:00:00"
	at...

可以看出,是格式轉換不正確,但是我找了好久也沒找到正確轉換格式的辦法

產生原因

容易發現,Jackson內置的沒有轉換·joda.DateTime`的方式,需要通過第三個Jar包或者自定義序列化/反序列化來解決這個問題

解決方案

  • 自定義Jackson中實體類的序列化和反序列化方式:
public class CustomDateSerializer extends JsonSerializer<DateTime> {

    private static DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");

    @Override
    public void serialize(DateTime value, JsonGenerator gen, SerializerProvider arg2) throws IOException {
        gen.writeString(formatter.print(value));
    }
}
public class CustomDateDeserializer extends JsonDeserializer<DateTime> {

    private static DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");

    @Override
    public DateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
        JsonNode node = jsonParser.getCodec().readTree(jsonParser);
        String s = node.asText();
        return DateTime.parse(s, formatter);
    }
}
  • 在DateTime類型的字段中加入註解:
	/**
     * 秒殺開始時間
     */
    @JsonSerialize(using = CustomDateSerializer.class)
    @JsonDeserialize(using = CustomDateDeserializer.class)
    private DateTime startDate;

    /**
     * 秒殺活動結束時間
     */
    @JsonSerialize(using = CustomDateSerializer.class)
    @JsonDeserialize(using = CustomDateDeserializer.class)
    private DateTime endDate;

這樣的話基本就完工了,同時也可以嘗試加入:

<dependency>
      <groupId>com.fasterxml.jackson.datatype</groupId>
      <artifactId>jackson-datatype-joda</artifactId>
      <version>2.9.8</version>
</dependency>

這個jar包,反序列化的結果會不一樣哦

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章