Jaskson精講第6篇-自定義JsonSerialize與Deserialize實現數據類型轉換
- 2020 年 9 月 24 日
- 筆記
Jackson是Spring Boot(SpringBoot)默認的JSON數據處理框架,但是其並不依賴於任何的Spring 庫。有的小夥伴以為Jackson只能在Spring框架內使用,其實不是的,沒有這種限制。它提供了很多的JSON數據處理方法、註解,也包括流式API、樹模型、數據綁定,以及複雜數據類型轉換等功能。它雖然簡單易用,但絕對不是小玩具,更多的內容我會寫成一個系列,5-10篇文章,請您繼續關注我。
- 《序列化與反序列化核心用法-JSON框架Jackson精解第1篇》
- 《特殊數據格式處理-JSON框架Jackson精解第2篇》
- 《屬性序列化自定義排序與字母表排序-JSON框架Jackson精解第3篇》
- 《@JacksonInject與@JsonAlias註解-JSON框架Jackson精解第4篇》
- 《@JsonCreator自定義反序列化函數-JSON框架Jackson精解第5篇》
本節繼續為大家介紹在Jackson序列化中經常遇到的一些特殊的數據類型,如LocalDateTime 。該如何進行序列化和反序列化。
一、LocalDateTime
反序列化異常
首先我們定義一個java POJO實體類,其中關鍵的成員變數時birthDate
,我們沒有採用Date數據類型,而是採用了Java8 新的日期類型LocalDateTime
,使用LocalDateTime
的好處我就不多說了,有很多的文章解釋說明。我們把精力放回到Jackson的JSON格式序列化與反序列化內容上來。
@Data
public class PlayerStar4 {
private String name; //姓名
private LocalDateTime birthDate; //出生日期
}
下面的程式碼,我們首先定義了一個PlayerStar4類的對象player,然後
- 使用writeValueAsString方法將player對象序列化為JSON字元串jsonString
- 然後使用readValue方法將JSON字元串jsonString ,反序列化為PlayerStar4類的對象
@Test
void testJSON2Object() throws IOException {
ObjectMapper mapper = new ObjectMapper();
PlayerStar4 player = new PlayerStar4();
player.setName("curry");//我並不知道庫里的生日,這裡是編造的
player.setBirthDate(LocalDateTime.of(1986,4,5,12,50));
//將player對象以JSON格式進行序列化為String對象
String jsonString = mapper.writeValueAsString(player);
System.out.println(jsonString);
//將JSON字元串反序列化為java對象
PlayerStar4 curry = mapper.readValue(jsonString, PlayerStar4.class);
System.out.println(curry);
}
但是上面的程式碼報錯了,從下圖中可以看出
- 將player對象序列化為JSON字元串jsonString 的過程被正常執行了,但是LocalDateTime序列化之後的結果,是圖中」黃框中的黃框「內容。
- 將JSON字元串反序列化的過程報錯了,因為Jackson默認情況下,根本不認識圖中」黃框中的黃框「內容這種LocalDateTime序列化之後的JSON字元串數據結構。無法把它反序列化為java對象。
怎麼辦?我們需要自定義序列化及反序列化類型轉換器,有兩種方法
- 繼承StdConverter類,自定義實現String與LocalDateTime相互轉換
- 繼承JsonSerializer和JsonDeserializer類,自定義實現String與LocalDateTime相互轉換
二、方法一:繼承StdConverter類
繼承StdConverter類,將LocalDateTime序列化為String數據類型
public class LocalDateTimeToStringConverter extends StdConverter<LocalDateTime, String> {
static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);
@Override
public String convert(LocalDateTime value) {
return value.format(DATE_FORMATTER);
}
}
繼承StdConverter類,將String數據類型反序列化為LocalDateTime
public class StringToLocalDatetimeConverter extends StdConverter<String, LocalDateTime> {
@Override
public LocalDateTime convert(String value) {
return LocalDateTime.parse(value, LocalDateTimeToStringConverter.DATE_FORMATTER);
}
}
自定義的轉換器完成之後,我們就可以在對應的成員變數上,使用@JsonSerialize
指定序列化轉換器,@JsonDeserialize
指定反序列化轉換器。
@JsonSerialize(converter = LocalDateTimeToStringConverter.class)
@JsonDeserialize(converter = StringToLocalDatetimeConverter.class)
private LocalDateTime birthDate;
然後調用第一小節中的測試用例,就不會出現異常了。控制台列印輸出結果如下,第一行是序列化結果JSON格式字元串,第二行是Java 對象的toString()方法的列印結果。
{"name":"curry","birthDate":"1986-4-5 12:50:00"}
PlayerStar4(name=curry, birthDate=1986-04-05T12:50)
三、方法二:繼承JsonSerializer和JsonDeserializer類
繼承JsonSerializer<LocalDateTime>
類,將LocalDateTime序列化為String數據類型
public class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);
@Override
public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider provider)
throws IOException {
String s = value.format(DATE_FORMATTER);
gen.writeString(s);
}
}
繼承JsonDeserializer<LocalDateTime>
類,將String數據類型反序列化為LocalDateTime
public class LocalDatetimeDeserializer extends JsonDeserializer<LocalDateTime> {
@Override
public LocalDateTime deserialize(JsonParser p, DeserializationContext ctx)
throws IOException {
String str = p.getText();
return LocalDateTime.parse(str, LocalDateTimeSerializer.DATE_FORMATTER);
}
}
四、如果上面的你都沒看懂
對於相對小白的讀者,上面的自定義序列化及反序列化轉換過程你都沒懂,對於LocalDateTime的異常你也不要慌,Jackson已經給出了解決方案。
需要特別和大家強調的是LocalDateTimeSerializer和LocalDateTimeDeserializer其實並不需要我們自己去定義,因為Jackson已經幫我們定義好了。 之所以我還做了自定義的實現的介紹,是因為要為大家講解這個自定義序列化和反序列化類型轉換的實現過程,以後你再遇到其他的特殊的數據類型轉換,或者LocalDateTime類型的特殊日期格式等,都可以自己來定義JsonSerialize和JsonDeserialize來實現數據類型的轉換。
下面的這兩個類就是Jackson已經幫我們定義好的LocalDateTimeSerializer和LocalDateTimeDeserializer。
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
使用方法是在對應的成員變數上,使用@JsonSerialize
指定序列化轉換器,@JsonDeserialize
指定反序列化轉換器。
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
private LocalDateTime birthDate;
執行之後的序列化和反序列化結果,和方法一、方法二自定義的實現效果是一樣的。
歡迎關注我的部落格,裡面有很多精品合集
- 本文轉載註明出處(必須帶連接,不能只轉文字):字母哥部落格。
覺得對您有幫助的話,幫我點贊、分享!您的支援是我不竭的創作動力! 。另外,筆者最近一段時間輸出了如下的精品內容,期待您的關注。
- 《手摸手教你學Spring Boot2.0》
- 《Spring Security-JWT-OAuth2一本通》
- 《實戰前後端分離RBAC許可權管理系統》
- 《實戰SpringCloud微服務從青銅到王者》
- 《VUE深入淺出系列》