Java JSON技术框架选型、测试及简单使用
Java JSON技术框架选型、测试及简单使用
(本文转载自’http://bbs.jee-soft.cn:8086/showtopic-155.aspx‘)
一、JSON????????JSON英文全称为JavaScript Object Natation,采用key:value键值对的方式存贮数据,与xml格式相比,JSON是一种轻量级的数据交换格式;不要被Javascript这个单词迷惑,实际上JSON只是一种数据格式,与具体语言并无关系。JSON已被广泛应用于业界,比如目前NoSQL数据库存贮大都采用key:value存贮结构,以Mongo为例,其脚本语法甚至直接使用Javascript;在数据传输时,采用JSON格式也被广泛应用,大部分开放API都开放JSON模式的数据输出;在ajax请求数据时,json格式也被广泛推transient的应用,在Mongo+Morphia开源项目下,如果对Java PO的成员指定transient,那么该成员数据将不会被存入Mongo数据库。另外一种应用场景就是这里要讲到的JSON,如果JAVA PO使用了Refrence(Mongo的Refrence)或者LazyLoading(可以理解成Hibernate LazyLoading概念),那么大部分的开源JAVA JSON相关项目,会自动加载这些Refrence、LazyLoading对象,如果PO形成相互引用,那就会形成死循环,即使没有形成死循环,大量不必要的数据被输出到客户端对资源的浪费也不容小觑。加上transient是一种解决办法。
三、基于JAVA的JSON主要开源项目及其对比?
????????Json开源项目非常多,如org.json、?JSON-Lib、jsontool、Jackson、Gson、SimpleJSON等等,后来专门查看了几种json开源测试数据对比后,决定采用Jackson。展示两组测试数据。首先来看大侠wangym(原博客http://wangym.iteye.com/blog/738933)对Jackson、JSON-Lib、Gson的测试结果
JSON转Bean,5个线程并发,约200字节对象,1千万次转换:
?
?JacksonJSON-libGson吞吐量64113.78067.413952.8总耗时(秒)1551238700
?
Bean转JSON,5个线程并发,约200字节对象,1千万次转换:
?
?JacksonJSON-libGson吞吐量5480215093.217308.2总耗时(秒)181661560
?
下面是参考Fastjson?的测试数据(http://www.iteye.com/topic/1113183)
性能对比
?
测试案例JSON-LibSimple-JSONFastjsonJacksonIntArray1000Decode3,6261,431563596StringArray1000Decode2,6982,283677774Map100StringDecode515597208230
?
功能对比
?
特性JSON-LibSimple-JSONFastjsonJackson序列化支持数组不支持不支持支持支持序列化支持Enum不支持不支持支持支持支持JavaBean不直接支持不直接支持支持支持支持hibernate laze不直接支持不直接支持支持支持循环引用支持支持支持支持
?
测试总结:1、显而易见,无论是哪种形式的转换,Jackson > Gson > Json-lib。
?????Jackson的处理能力甚至高出Json-lib有10倍左右
2、JSON-lib似乎已经停止更新,最新的版本也是基于JDK15,而Jackson的社区则较为活跃;
3、在测试性能的同时,又以人肉方式对这三个类库转换的正确性进行了检查,三者均达100%正确;
4、JSON-lib在转换诸如Date类型时较为累赘,如以下是两者的转换结果:
JSON-lib:
{"brithday":{"date":17,"day":2,"hours":9,"minutes":24,"month":7,"seconds":26,"time":1282008266398,"timezoneOffset":-480,"year":110}}
Jackson:
{"brithday":1282008123101}
5、JSON-lib依赖commons系列的包及ezmorph包共5个,而Jackson除自身的以外只依赖于commons-logging
6、Jackson提供完整基于节点的Tree Model,以及完整的OJM数据绑定功能。
四、为什么选择Jackson?
参考博文(http://blog.csdn.net/chaijunkun/article/details/7208828)
??????最近在研究JSON,Java中有很多处理JSON的类库,lib-json、sf-json、fastjson还有Jackson Json。第一个就不说了,性能和功能都没有什么亮点。
sf-json最大的优点就是随机读取方便。代码很简单:
JSONObject json= JSONObject.fromObject(str);
然后读取字段内容:
json.getString或者getInt之类的。但是工作效率有待商榷,而且容易出错。
另外sf-json还有个优点就是自动使用unicode编码,当内容中出现中文或者符号的时候会自动将其转换为\uFFFF这样的unicode编码。这样即便是在web服务器端的response中没有设置编码,直接推送json也不会出现乱码问题。
????fastjson,顾名思义就是快。网上已经有很多性能对比的数据了,我就不多说其性能了。
??????这里要说的就是它的功能性问题。可能是定位不一样,最初fastjson就是要快,因此在对象的序列化与反序列化上下了很大功夫。但是在功能上有所缺乏。
不知在哪个版本开始加上了key按字典排序的功能。但是貌似这个功能没有办法关闭。有些时候我是不希望字段顺序被打乱的,这个问题就无法解决。
我使用的fastjson版本为1.1.14。另外fastjson还有一些bug没有解决,而且是比较明显的bug。例如在@JsonField注解中format参数,这个是用来指—ate类型数据如何序列化的。如果你使用英文或符号,OK,没有问题(例如yyyy-MM-dd),但是格式中一旦出现中文就会出错(例如yyyy年MM月dd日)。而且经过实验,所有的注解都要放在属性的Getter(就是getXXX()方法)上,直接放在属性上是无法工作的。在eclipse中,一般我们都是直接写属性,属性写完后用自动生成的方式生成Getter和Setter方法。如果今后该类的属性发生变化了,个人更倾向于直接删除所有Getter和Setter,然后重新生成。那么假如把注解全放到Getter上面,我删的时候就要非常小心。
再有一个比较致命的就是文档。几乎找不到全面的文档来介绍或支持fastjson。整个项目都由一个名为“温少”的人来负责,存在很多不确定的因素。
经过个人的评估,我更倾向于使用Jackson Json。首先说文档,Jackson Json官方网站上对每一个版本都有详尽的文档(http://jackson.codehaus.org/)。另外Jackson Json的序列化与反序列化速度也并不见得有多慢。更重要的是它的注解支持要好于fastjson。就拿刚才说到的key按字典排序的功能吧,可以在实体类上直接加上@JsonPropertyOrder(alphabetic=false)注解就可以关闭排序功能。而对于其他功能的注解支持也很好。
例如Date的序列与反序列化注解支持
@JsonSerialize(using=DateSerializer.class)
@JsonDeserialize(using=DateDeserializer.class)
private Date birthday;
这样就能指定对birthday字段的序列化与反序列化方法。另外,这两个注解都直接放在了属性上,没有放在Getter上。
针对上面的两个注解,我的序列化器是这样写的
public class DateSerializer extends JsonSerializer<Date>
继承了JsonSerializer,泛型中指定了序列化类型为Date,然后重写如下方法
@Override
public void serialize(Date date, JsonGenerator gen, SerializerProvider provider) throws IOException, JsonProcessingException
方法中传进来的date就是将要被序列化的数据,接下来你可以任意展示该数据,在退出该方法之前使用gen.writeString(formattedDate);来完成序列化就可以了。
类似地,我的反序列化器是这样写的:
public class DateDeserializer extends JsonDeserializer<Date>
继承了JsonDeserializer,泛型中指定了反序列化类型为Date,然后重写如下方法
@Override
public Date deserialize(JsonParser parser, DeserializationContext context)throws IOException, JsonProcessingException {
这里面方法的返回值就是反序列化后的最终内容。方法内部你可以使用parser.getText()来获取到当前要处理的内容。你可以随便折腾里面的数据,只需要最后返回你想要的Date就可以了。
另外在制作基于Jackson Json的Service时想使用泛型的思想来写一个接口,最终目的就是希望方法能随着参数类型不同,返回值的类型也随之不同。以前很少写泛型的方法,这个问题虽然基础,但是难住了我,经过查看Jackson Json的源代码,我得到了启示,像下面这样写就OK了:
public <T> T strToObj(String jsonStr, Class<T> clazz)
这样写就可以了。假设我有一个Result类型的对象需要反序列化,当前已经有了一个json字符串jsonStr,那么我只需要指定第二个参数clazz就可以直接得到Result类型的对象了:
- Result newResult= jsonProcessService.strToObj(jsonStr, Result.class);
这样就不用在方法前加入(Result)类型强制转换了。
五、Jackson区别于竞争对手的7个杀手锏参考博文(http://hi.baidu.com/suofang/blog/item/60e7316d9a1e99db4216946b.html)
Jackson JSON?处理器?为一行之有效的Java JSON处理器,诸如它具有如下特点:?
- 简但且方便的JSON解析,以及与Java对象的相互转换。?
- 通过注释(annotations)和配置(settings)可扩展的配置性。?
- 超快的基于流的解析性能,以及完整的数据绑定。
但许多其他Java的JSON库仅考虑方便性和配置性,性能反倒不是面向用户的最重要层面。
那么,为何Java开发人员不选择Jackson而放弃其竞争产品呢?
以上功能的简短列表其实不过是Jackson功能的冰山一角。 的确,这三个常见功能是重要的,但某种程度上也仅是最基本的东西,起码,JSON处理器应被作为值得考虑的工具使用。除此之外,还有很多很多功能应该提供,而这也正是Jackson具备的能力。
因此,让我们来看看7个样例 -- 吉祥的数字 -- "杀手锏" --Jackson近年来领先竞争对手的几点,依据先后顺序介绍(始于1.0版,最新的一个特性是1.6版加入的)。
1.多处理模式,且可很好协作
从基本开始,有多种方法来使用和生产JSON数据,尽管多数JSON包仅提供单一的处理方式,但却有三种互补的JSON处理方式(详细解释见:There are Tree ways...):- 增量解析及生成(流模式)。高性能,低开销的顺序访问。这是最低级的处理方法,相当于用于处理XML的SAX和StAX API。所有包装内部必须有这样的分析器,但并非所有都公开。?
- 基于树的数据模式(JSON DOM)。?树是一种描述JSON内容的自然的概念模型,因此许多软件包提供将JSON作为逻辑树处理的功能。这是一个灵活的模式,可很好适用某类任务,原型处理或即席访问也相当杰出。?
- 数据绑定(JSON?与POJO相互转换。极为方便,通常较树状模式更高的存取效率,也是适于Java开发人员通用的自然的数据绑定方式。常用于大多数Java REST框架,诸如JAX-RS。
尽管多角度的好处显而易见,且各自提供最佳的用例,很少有(如果有的话?)其他的Java JSON包提供这些规范的处理模式。
大多数只提供一个模式(org.json以树组织数据; an>技术2部","depDesc":"技术2部","depLevel":3,"parentId":10000,"path":"0.1.10000.10002.","orgType":2,"creatorId":1,"createtime":"2012-07-18 10:38:47","updateId":1,"updatetime":"2012-07-18","sn":null,"chargeIds":"","chargeNames":"","demension":{"version":null,"orgId":null,"orgPath":null,"demId":1,"demName":"行政维度","demDesc":"行政维度","demType":1,"organizations":[]}},{"version":null,"orgId":null,"orgPath":null,"depId":1,"depName":"宏天软件","depDesc":"宏天软件","depLevel":1,"parentId":0,"path":"0.1.","orgType":1,"creatorId":1,"createtime":"2011-08-29 00:00:00","updateId":1,"updatetime":"2011-08-29","sn":null,"chargeIds":"","chargeNames":"","demension":{"version":null,"orgId":null,"orgPath":null,"demId":1,"demName":"行政维度","demDesc":"行政维度","demType":1,"organizations":[]}},{"version":null,"orgId":null,"orgPath":null,"depId":10001,"depName":"技术1部","depDesc":"技术1部","depLevel":3,"parentId":10000,"path":"0.1.10000.10001.","orgType":2,"creatorId":1,"createtime":"2012-07-18 10:38:15","updateId":1,"updatetime":"2012-07-18","sn":null,"chargeIds":"","chargeNames":"","demension":{"version":null,"orgId":null,"orgPath":null,"demId":1,"demName":"行政维度","demDesc":"行政维度","demType":1,"organizations":[]}}]???? [{version=null, orgId=null, orgPath=null, depId=10000, depName=技术部, depDesc=null, depLevel=2, parentId=1, path=0.1.10000., orgType=1, creatorId=1, createtime=2012-07-18 10:37:56, updateId=1, updatetime=2012-07-18, sn=null, chargeIds=10020, chargeNames=超级管理员, demension={version=null, orgId=null, orgPath=null, demId=1, demName=行政维度, demDesc=行政维度, demType=1, organizations=[]}}, {version=null, orgId=null, orgPath=null, depId=10002, depName=技术2部, depDesc=技术2部, depLevel=3, parentId=10000, path=0.1.10000.10002., orgType=2, creatorId=1, createtime=2012-07-18 10:38:47, updateId=1, updatetime=2012-07-18, sn=null, chargeIds=, chargeNames=, demension={version=null, orgId=null, orgPath=null, demId=1, demName=行政维度, demDesc=行政维度, demType=1, organizations=[]}}, {version=null, orgId=null, orgPath=null, depId=1, depName=宏天软件, depDesc=宏天软件, depLevel=1, parentId=0, path=0.1., orgType=1, creatorId=1, createtime=2011-08-29 00:00:00, updateId=1, updatetime=2011-08-29, sn=null, chargeIds=, chargeNames=, demension={version=null, orgId=null, orgPath=null, demId=1, demName=行政维度, demDesc=行政维度, demType=1, organizations=[]}}, {version=null, orgId=null, orgPath=null, depId=10001, depName=技术1部, depDesc=技术1部, depLevel=3, parentId=10000, path=0.1.10000.10001., orgType=2, creatorId=1, createtime=2012-07-18 10:38:15, updateId=1, updatetime=2012-07-18, sn=null, chargeIds=, chargeNames=, demension={version=null, orgId=null, orgPath=null, demId=1, demName=行政维度, demDesc=行政维度, demType=1, organizations=[]}}]
- 增量解析及生成(流模式)。高性能,低开销的顺序访问。这是最低级的处理方法,相当于用于处理XML的SAX和StAX API。所有包装内部必须有这样的分析器,但并非所有都公开。?