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.以上內容僅代表個人觀點和一小部分實踐,歡迎大家一起探討。
作者:京東物流 吳憲彬
來源:京東雲開發者社區