Java常用的JSON序列化與反序列化工具實踐

JSON簡介:

JSON(Java Script Object Notation)是一種輕量級的數據交換格式,通常用於在不同系統之間傳輸數據。它基於 JavaScript 對象語法,但已成爲一種獨立於語言的格式。JSON 數據以鍵值對的形式組織,易於閱讀和編寫。

爲什麼要使用 JSON?

1.簡單易用:JSON的語法簡單,易於理解和編寫,可以快速地進行數據交換。

2.跨平臺支持:JSON可以被多種編程語言解析和生成,可以在不同的平臺和語言之間進行數據交換和傳輸。

3.數據交換格式:JSON是一種標準的數據交換格式,可以在Web應用程序中廣泛使用,如前後端數據交互、API接口數據傳輸等。

4.輕量級:JSON的數據格式輕量級,傳輸數據時佔用帶寬較小,可以提高數據傳輸速度。

5.易於擴展:JSON的數據結構靈活,支持嵌套對象和數組等複雜的數據結構,便於擴展和使用。

6.安全性:JSON數據格式是一種純文本格式,不包含可執行代碼,不會執行惡意代碼,因此具有較高的安全性。

什麼時候會使用 JSON?

1.前後端數據傳輸:當Web應用程序需要進行前後端數據傳輸時,可以使用JSON格式來傳輸數據,以便前後端之間進行數據交互。

2.API接口數據傳輸:當使用API接口進行數據傳輸時,可以使用JSON格式來傳輸數據,以便多個系統之間進行數據交互。

3.存儲數據:當需要存儲數據時,可以使用JSON格式來存儲數據,以便後續的讀取、修改和刪除等操作。

4.日誌記錄:當需要記錄日誌時,可以使用JSON格式來記錄日誌信息,以便後續的分析和查詢。

5.配置文件:當需要存儲配置文件時,可以使用JSON格式來存儲配置信息,以便後續的讀取和修改操作。



JSON序列化與反序列化實踐。

java中比較常用的JSON工具 fastjson,fastjson2,jackson,gson。實踐的內容是新增字段的場景,各個工具的兼容性以及不同工具間的兼容性。

前置條件

各個JSON工具的版本號:

fastjson

 <dependency>
     <groupId>com.alibaba</groupId>
     <artifactId>fastjson</artifactId>
     <version>1.2.83-jdsec.rc1</version>
 </dependency>

fastjson2

<dependency>
    <groupId>com.alibaba.fastjson2</groupId>
    <artifactId>fastjson2</artifactId>
    <version>2.0.48</version>
</dependency>

jackson

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.7.9</version>
</dependency>

gson

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.8</version>
</dependency>

實體類:

現在三個類 Person 、OldFamily、Family三個類,Family是在OldFamily中增加了新屬性oldPerson。主要是爲了模擬數據處理時,新老數據的兼容問題。

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Person {
    private String name;
    private int age;
    private int sex;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Family {
    private Person yongPerson;
    private Person oldPerson;
    private List<Person> persons;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class OldFamily {

    private Person yongPerson;

    private List<Person> persons;
}

fastjson序列化與反序列化





通過程序運行結果,可以觀察到在Family序列化結果中,persons屬性中的第三個person實例是oldPerson實例的引用,而yongPerson屬性的值是persons屬性中下標爲0的實例的引用。這已經不是標準的JSON格式,而是fastjson的特性。當增加oldPerson屬性後,Family序列化的結果在反序列化爲OldFamily對象實例時,persons屬性中有一個person實例爲空。雖然反序列化不會報錯,但程序將無法得到預期的結果。



爲解決這個問題,fastjson在序列化時是默認的順序是按照屬性字段的字母順序排序。你也可以通過註解的方式指定順序,將新增加的屬性放到orders的最後。

@JSONType(orders={"yongPerson", "persons", "oldPerson"})
public class Family {

    private Person yongPerson;

    private List<Person> persons;

    private Person oldPerson;

}





通過序列化結果可以看到oldPerson這個新增加的屬性已經引用了persons屬性中下標爲2的實例。反序列化之後的OldFamily對象persons屬性中的三個實例都有值,不會再有null值。程序還可以確保正確運行。



fastjson1.X 可以通過SerializerFeature參數來輸出標準JSON格式

public static String toJSONString(Object object, SerializerFeature... features) {
    return toJSONString(object, DEFAULT_GENERATE_FEATURE, features);
}





通過程序運行結果可以看出,當指定序列化參數SerializerFeature.DisableCircularReferenceDetect時,是以標準的Json格式輸出。



fasJson2序列化與反序列化

在fastjson2中,將對象序列化爲JSON格式時,默認情況下就是標準的JSON格式。你可以通過設置com.alibaba.fastjson2.JSONWriter.Feature參數值爲`JSONWriter.Feature.ReferenceDetection





即使用標準的JSON格式作爲默認序列化方式是合理的。非標準化的方式應當需要特殊指定。在使用fastjson2版本2.0.26時,當設置com.alibaba.fastjson2.JSONWriter.Feature參數值爲JSONWriter.Feature.ReferenceDetection時,會導致序列化和反序列化成Family實例結果得不到預期結果。

而在反序列化爲OldFamily實例結果正確是因爲沒有oldPerson屬性。



然而,在最新的2.0.48版本中,可以正常進行序列化和反序列化。以下是fastjson2的2.0.48版本的運營結果





gson序列化與反序列化

在gson中,默認情況下,當在Fimaly類中新增了oldPerson屬性時,Fimaly的序列化結果可以正確地反序列化成OldFimaly類的實例。





Jackson序列化與反序列化

Jackson默認情況下,當在Fimaly類中新增了oldPerson屬性時,Fimaly類的序列化結果無法正確反序列化成OldFimaly類實例。是因爲Jackson在默認情況下進行反序列化時,要求所有屬性都必須存在才能正確反序列化。







解決方案1 通過代碼設置ObjectMapper中DeserializationFeature的屬性

objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);





解決方案2 在類上使用

com.fasterxml.jackson.annotation.JsonIgnoreProperties(ignoreUnknown = true)









在使用jackson進行序列化和反序列化時,最好指定不進行屬性檢測。否則,在類新增屬性的情況下就無法實現兼容。

fastjson默認序列化fastjson2反序列化





通過測試結果可以看出,fastjson2可以反序列化出fastjson默認序列化的json結果,說明了fastjson2兼容了fastjson。畢竟都是阿里出品。

fastjson2序列化fastjson反序列化





通過測試結果可以看出,fastjson2可以反序列化出fastjson默認序列化的json結果,說明了fastjson2兼容了fastjson。畢竟都是阿里出品。



fastjson默認序列化 jackson反序列化





通過結果可以看出,使用jackson進行反序列化時,沒有指定了DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES爲false,那麼默認值爲true,會把“$ref”作爲屬性進行檢測,無論是OldPerson還是Person都沒有此屬性。會拋出異常。







通過結果可以看出,使用jackson進行反序列化時,指定了DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES爲false沒有報異常,但是person對象是以屬性的默認值實例化的,沒有得到想要的結果。

fastjson默認序列化gson反序列化





通過結果可以看出,使用gson進行反序列化時沒有報異常,但是person對象是以屬性的默認值實例化的,沒有得到預期結果。

總結:



1.使用fastjson時,默認的序列化方式會對於具有相同對象的多個引用,除了第一個會以標準的JSON文本輸出,其他引用會以“$ref”的方式輸出文本。爲了以標準的JSON格式輸出文本,可以使用SerializerFeature.DisableCircularReferenceDetect參數。而fastjson2的默認序列化輸出是標準的JSON格式,若需要具有fastjson默認序列化特性的場景,可以指定com.alibaba.fastjson2.JSONWriter.Feature參數值爲JSONWriter.Feature.ReferenceDetection

2.在使用fastjson或者fastjson2的特性,具有相同對象的多個引用,除了第一個會以標準的JSON文本輸出,其他引用會以“$ref”的方式輸出文本。在新增類屬性字段的情況下,一定要把新增的屬性放到最後序列化,確保在反序列化成沒有新增屬性類實例時,得不到預期結果造成線上事故。

3.fastjson和fastjson2在一定程度上是兼容的,但也存在版本差異和Bug,因此在使用時需要進行充分的測試驗證。另外,gson、jackson和fastjson2的默認序列化方式也是標準JSON格式。對於jackson,若要在反序列化時兼容不存在的屬性的JSON文本成爲對象實例,需要設定DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES爲false。

4.在使用JSON序列化工具時,需要注意每個工具的特點,尤其是在使用各自具有的特性時,要留意兼容性問題。在進行JSON工具版本升級時,也要進行充分的測試驗證,確保有單元測試來保證質量。

5.若作爲與外部系統交互的JSON格式數據,需要以標準化的數據格式進行存儲或傳輸。

6.以上內容僅代表個人觀點和一小部分實踐,歡迎大家一起探討。

作者:京東物流 吳憲彬

來源:京東雲開發者社區

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