Java常用的JSON序列化与反序列化工具实践
JSON简介:
JSON(Java Script Object Notation)是一种轻量级的数据交换格式,通常用于在不同系统之间传输数据。它基于 JavaScript 对象语法,但已成为一种独立于语言的格式。JSON 数据以键值对的形式组织,易于阅读和编写。
为什么要使用 JSON?
什么时候会使用 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序列化与反序列化
![](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2024-04-10-15-46ypPuKKoiMgu28KTy.png)
通过程序运行结果,可以观察到在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;
}
![](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2024-04-10-15-46c8cChEitUZBBinI.png)
通过序列化结果可以看到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);
}
![](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2024-04-10-15-463GFUCIH6yk46rafF.png)
通过程序运行结果可以看出,当指定序列化参数SerializerFeature.DisableCircularReferenceDetect时,是以标准的Json格式输出。
fasJson2序列化与反序列化
在fastjson2中,将对象序列化为JSON格式时,默认情况下就是标准的JSON格式。你可以通过设置`com.alibaba.fastjson2.JSONWriter.Feature`参数值为`JSONWriter.Feature.ReferenceDetection
![](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2024-04-10-15-46RZvzvs7TZ3hMfc4.png)
即使用标准的JSON格式作为默认序列化方式是合理的。非标准化的方式应当需要特殊指定。在使用fastjson2版本2.0.26时,当设置`com.alibaba.fastjson2.JSONWriter.Feature`参数值为`JSONWriter.Feature.ReferenceDetection`时,会导致序列化和反序列化成Family实例结果得不到预期结果。
而在反序列化为OldFamily实例结果正确是因为没有oldPerson属性。
然而,在最新的2.0.48版本中,可以正常进行序列化和反序列化。以下是fastjson2的2.0.48版本的运营结果
![](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2024-04-10-15-46mJtbCUlGWH0cKB4.png)
gson序列化与反序列化
在gson中,默认情况下,当在`Fimaly`类中新增了`oldPerson`属性时,`Fimaly`的序列化结果可以正确地反序列化成`OldFimaly`类的实例。
![](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2024-04-10-15-46x10ue460pQAwv10QiT.png)
Jackson序列化与反序列化
Jackson默认情况下,当在`Fimaly`类中新增了`oldPerson`属性时,`Fimaly`类的序列化结果无法正确反序列化成`OldFimaly`类实例。是因为Jackson在默认情况下进行反序列化时,要求所有属性都必须存在才能正确反序列化。
![](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2024-04-10-15-46HxF6noJlK9qYiPP.png)
解决方案1 通过代码设置ObjectMapper中DeserializationFeature的属性
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
![](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2024-04-10-15-46FFdnf28yrtWM46b284.png)
解决方案2 在类上使用
com.fasterxml.jackson.annotation.JsonIgnoreProperties(ignoreUnknown = true)
![](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2024-04-10-15-46hKGRqwIGF4EkB8S.png)
![](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2024-04-10-15-46qdcHggqvIBoOLWF.png)
在使用jackson进行序列化和反序列化时,最好指定不进行属性检测。否则,在类新增属性的情况下就无法实现兼容。
fastjson默认序列化fastjson2反序列化
![](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2024-04-10-15-46VVyEK8O0UyesBWW.png)
通过测试结果可以看出,fastjson2可以反序列化出fastjson默认序列化的json结果,说明了fastjson2兼容了fastjson。毕竟都是阿里出品。
fastjson2序列化fastjson反序列化
![](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2024-04-10-15-46cV6n3AuZtm0cAgv.png)
通过测试结果可以看出,fastjson2可以反序列化出fastjson默认序列化的json结果,说明了fastjson2兼容了fastjson。毕竟都是阿里出品。
fastjson默认序列化 jackson反序列化
![](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2024-04-10-15-46zKqYyeTvAvvioo46.png)
通过结果可以看出,使用jackson进行反序列化时,没有指定了DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES为false,那么默认值为true,会把“$ref”作为属性进行检测,无论是OldPerson还是Person都没有此属性。会抛出异常。
![](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2024-04-10-15-46YzLsYhh3k86weTa.png)
通过结果可以看出,使用jackson进行反序列化时,指定了DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES为false没有报异常,但是person对象是以属性的默认值实例化的,没有得到想要的结果。
fastjson默认序列化gson反序列化
![](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2024-04-10-15-46cLwAY7GtQF0MLNS.png)
通过结果可以看出,使用gson进行反序列化时没有报异常,但是person对象是以属性的默认值实例化的,没有得到预期结果。
总结: