写点什么

Java 常用的 JSON 序列化与反序列化工具实践

  • 2024-05-20
    北京
  • 本文字数:3695 字

    阅读完需:约 12 分钟

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@ToStringpublic class Person {    private String name;    private int age;    private int sex;}
复制代码


@Data@Builder@NoArgsConstructor@AllArgsConstructorpublic class Family {    private Person yongPerson;    private Person oldPerson;    private List<Person> persons;}
复制代码


@Data@Builder@NoArgsConstructor@AllArgsConstructorpublic 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.以上内容仅代表个人观点和一小部分实践,欢迎大家一起探讨。


作者:京东物流 吴宪彬


来源:京东云开发者社区

发布于: 刚刚阅读数: 3
用户头像

拥抱技术,与开发者携手创造未来! 2018-11-20 加入

我们将持续为人工智能、大数据、云计算、物联网等相关领域的开发者,提供技术干货、行业技术内容、技术落地实践等文章内容。京东云开发者社区官方网站【https://developer.jdcloud.com/】,欢迎大家来玩

评论

发布
暂无评论
Java常用的JSON序列化与反序列化工具实践_京东科技开发者_InfoQ写作社区