Json常用序列化工具包大比拼
一、前言
Json已成为计算机编程中最常用的数据传输和存储格式之一,所以对Json的序列化和反序列化工具的选择也是互联网系统中比较重要的环节,尤其在高并发下的执行效率,可能会直接影响系统的吞吐率。本文将从功能和性能两方面对常用的四种Json处理工具进行对比,以便选出符合我们系统需要的Json处理工具。
二、功能对比
项目 |
json-lib |
fastJson |
Jackson |
Gson |
最新版本号 |
2.4 |
1.2.51 |
2.97 |
2.8.5 |
最后更新 |
2010/12/14 |
2018/9/30 |
2018/9/19 |
2018/5/22 |
被引用次数 |
426 |
1492 |
5185 |
8655 |
是否支持注解 |
No |
Yes |
Yes |
Yes |
Map中的key为Long时 |
报错 |
正常输出,不是标准格式 |
会把key转成String |
会把key转成String |
特殊字符 |
支持 |
支持 |
支持 |
支持 |
控制字符 |
支持 |
支持 |
支持 |
支持 |
表情字符 |
支持 |
支持 |
支持 |
支持 |
从上表可以得出以下结论:
- Sf的json-lib已经很久没有更新了,其它三种都还一直在更新维护
- 从Maven库中被引用的次数来看,sf的json-lib也是使用的最少的,而Gson和Jackson被使用的较多
- 当对象中包含key为Long类型的Map时,json-lib序列化时会报错,fastJson是正常以整数作为key输出,Jackson和Gson会把key转换成字符串输出。fastJson的处理方式会导致反序列化报错
- 经测试,四个工具包对特殊字符的处理都没有问题
其它说明:
1、 Jackson、json-lib反序列化时,要求所有涉及的Bean必须存在默认的构造函数
2、 fastJson、json-lib反序列化,再序列化之后得到的JSON与之前可能不一致,因为Map的顺序会变,而Jackson、gson反序列化之后是一致的,其使用了LinkedHashMap保证顺序
3、 fastJson、Gson输出json时会忽略值为null的字段;对于值为null的字段,jackson输出null,而json-lib输出空字符串
4、 fastJson反序列化时,二级对象中的List出现过没有被反序列化的情况,但后来测试又可以反序列化了,目前还没有找到规律
三、性能对比
1) 序列化操作
第一组:
测试环境:本地Windows、2核8G内存,64位OS
Bean对象:小对象,输出Json后约1.83KB
结论:
- 对于小对象的序列化,json-lib在高并发的情况下效率明显不如其它三个工具,同时json-lib的CPU占用率达到100%
- fastJson、Jackson和Gson对小对象的序列化执行效率差异不明显,但Jackson更优
第二组:
测试环境:本地Windows、2核8G内存,64位OS
Bean对象:大对象,输出Json后约8.99KB
结论:
- 对于大对象,sf的json-lib执行效率明显不如其它三个工具。在高并发的情况下,Jackson的执行效率几乎是json-lib的10倍;
- Gson的执行效率也明显不如fastJson和Jackson,消耗时间几乎是它们的2倍;
- 执行效率上,Jackson优于fastJson
- Gson对CPU的占用率控制的最好,一直在80%左右
第三组:
测试环境:本地Windows、2核8G内存,64位OS
Bean对象:特大对象,输出Json后约56.1KB。因在小对象测试中证明json-lib和gson在高并发下效率不好,所以大对象测试中忽略这两个包,只对比fastjson和jackson。
结论:
- 执行效率上,Jackson优于fastJson。网上很多朋友都说fastjson比jackson快,可能是使用了jackson1.x的缘故,后面有时间再测试一下。
2) 反序列化操作
第一组:
测试环境:本地Windows、2核8G内存,64位OS
输入数据:小对象,输入Json约1.83KB
总结:
- 对于小文件的反序列化,json-lib效率明显不行
- 在高并发的情况下,Jackson的效率最优
- 对于小文件的反序列化操作,即使高并发的情况下,CPU占用率也表现比较平稳,相对来说fastJson的CPU占用率更高
第二组:
测试环境:本地Windows、2核8G内存,64位OS
输入数据:大对象,输入Json约9.83KB
结论:
- 对于大文件的反序列化,json-lib和Gson的执行效率明显不如fastJson和Jackson
- 高并发的情况下,Jackson的执行效率优于fastJson
第三组:
测试环境:本地Windows、2核8G内存,64位OS
输入数据:特大对象,输入Json约56.1KB
结论:
- 对于更大文件的反序列化,json-lib和Gson的执行效率明显不如fastJson和Jackson
- Jackson的执行效率优于fastJson,尤其是高并发的情况下
四、总结
经过以上测试及对比,基本可以得出结论:Jackson工具包(测试中使用2.9.5版本)在功能和性能方面都表现的更出色,在新开发系统时可以考虑使用Jackson进行JSON数据的处理。理由如下:
- Jackson使用广泛,并且仍然在持续更新
- Jackson对特殊字符支持完好
- 在序列化和反序列化时,Jackson的性能在测试的4个工具包中表现最优,尤其是对大文件或高并发时表现更好。
五、使用Jackson的注意事项
在使用Jackson时,有一些注意事项,需要在编写代码时注意,具体如下:
1) 反序列化时,要求所有涉及的Bean必须存在默认的构造函数,否则会报错;
2) 反序列化时,如果json中有部分字段是对象中不存在的属性,或对象中无get/set方法,会报“UnrecognizedPropertyException”,解决方法是:
在类中添加 @JsonIgnoreProperties(ignoreUnknown = true),
或者代码中设置:
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
3) 反序列化的类是抽象类或者接口,就会导致“Can not construct instance of”这个异常。
解决方法:添加@JsonDeserialize(as = Cat.class)注解
如下:
Json文件:
{"id":1001,"name":"布莱德","weight":1.67,"animal":{"color":"Blue"}}
4) 当反序列化的JSON中包含了单引号而不是双引号的时候,会抛“Unexpected character (''' (code 39))”异常,
如Json:{"id":1001,"name":'布莱德','weight':1.67, "feild1": 56}
解决方法:
JsonFactory factory = new JsonFactory();
factory.enable(JsonParser.Feature.ALLOW_SINGLE_QUOTES);
ObjectMapper mapper = new ObjectMapper(factory);
六、Jackson从1.x迁移到2.x的步骤
1) 修改POM文件
旧依赖 |
新依赖 |
<dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-mapper-asl</artifactId> <version>1.x.x</version> </dependency> |
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.5</version> </dependency> |
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>1.x.x</version> </dependency> |
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.5</version> </dependency> |
2) 包名更改
所有以org.codehaus.jackson开头的包名都替换成com.fasterxml.jackson开头的。
3) 设置属性的代码调整
SerializationConfig.Feature.* 改成 SerializationFeature.*
DeserializationConfig.Feature.* 改成 DeserializationFeature.*