本文中所讲的所有代码都在此:json-test
目前关于java与json互转的工具包有很多 ,主流的主要有以下几个 :
- json-lib (依赖于 ezmorph、commons-beanutils、commons-collections、groovy-all、oro、xom)
- gson
- flexjson
- fastjson
- jackson
改天将各个工具包的特性(包括使用方便程度、序列化与反序列化的性能)列出来,便于大家使用,目前仅发现flexjson是最使用上简洁的、无依赖的工具包,能够轻松实现复杂的(树型多层结构,并且允许不同层对象中包含相同字段名)POJO转json。
1、json-lib
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
//
java -> json Classes
sourceBean = TestCommon.getTestBean(); JsonConfig
jc = new
JsonConfig(); //
默认日期转换后的格式:"birthday":{"date":1,"day":3,"hours":0,"minutes":0,"month":0,"seconds":0,"time":-5364691200000,"timezoneOffset":-480,"year":-100} //
这里添加格式自定义转换,解决默认日期格式不堪直视的问题。不加也可以,json-lib会把Date中所有字段输出出来,搞晕你。。。 jc.registerJsonValueProcessor(Date. class ,
new
JsonDateValueProcessor()); //
过滤掉为空的属性,json-lib默认会将为空的String初始化为"",为空的Number初始化为0,总之不会为null。对于POJO来说,这种做法没法区分包装类型是否为空,所以某种意义上来说 //
,json-lib多此一举了。 jc.setJsonPropertyFilter( new
PropertyFilter() { public
boolean
apply(Object source, String name, Object value) { if
(value == null )
{ return
true ; } return
false ; } }); JSONObject
jsonObject = JSONObject.fromObject(sourceBean, jc); String
jsonStr = jsonObject.toString(); System.out.println( "java->json:"
+ jsonStr); /**
json -> java */ JSONUtils.getMorpherRegistry().registerMorpher( new
DateMorpher( new
String[] { "yyyy-MM-dd
HH:mm:ss" ,
"yyyy-MM-dd"
})); jc
= new
JsonConfig(); jc.setRootClass(Classes. class );
//
指定需要转换到的根类的类型。 //
问题来了,那么内部集合对应的类型哪里指定呢?通过测试发现,如果不指定会出现只有父类(Classes)会转换成原始的Bean,而其集合(students)属性会被自动转换成MorphDynaBean,这时候如果迭代这个List中对象,会抛出异常:java.lang.ClassCastException: //
net.sf.ezmorph.bean.MorphDynaBean cannot be cast to com.zt.test.Student //
关于这个问题,官方并没有明确指明,但通过查看源码发现有一个方法能解决这个问题:JSONObject.setClassMap //
,该方法的官方声明【Sets the current attribute/Class Map ;classMap : a Map of classes, every key identifies a property or a regexp 】 //
通过查看源码发现这就是我们想要的,通过它可以指定内部集合中包含的复合对象的类型,如果该内部类型中还包含了其它集合,处理 方法一样,统统加如到classMap中去,如下: Map<String,
Class> classMap = new
HashMap<String, Class>(); classMap.put( "students" ,
Student. class );
//指定Classes的students字段的内部类型 jc.setClassMap(classMap); JSONObject
targetJo = JSONObject.fromObject(jsonStr, jc); Classes
targetBean = (Classes) JSONObject.toBean(targetJo, jc); System.out.println( "json->java:"
+ BeanUtils.describe(targetBean)); assertEquals(targetBean.getStudents().get( 0 ).getName(),
"张扇风" ); |
2、gson
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
package
com.zt.test; import
junit.framework.TestCase; import
com.google.gson.Gson; public
class
GsonTest extends
TestCase { public
void
testGson() throws
Exception { Classes
sourceBean = TestCommon.getTestBean(); Gson
gson = new
Gson(); //
java -> json String
json = gson.toJson(sourceBean); //
System.out.println(json); //
json -> java Classes
targetBean = gson.fromJson(json, Classes. class ); //
System.out.println(BeanUtils.describe(targetBean)); assertEquals(targetBean.getStudents().get( 0 ).getName(),
"张扇风" ); assertEquals(targetBean.getStudents().get( 0 ).getBirthday(),
TestCommon.DATEFORMAT.parse( "1800-01-01
01:00:00" )); } public
void
testLoad() throws
Exception { for
( int
i = 0 ;
i < 100000 ;
i++) { testGson(); } } } |
3、flex-json
1
2
3
4
5
6
7
8
9
10
11
12
13
|
//
java -> json Classes
sourceBean = TestCommon.getTestBean(); JSONSerializer
serializer = new
JSONSerializer(); String
jsonStr = serializer.deepSerialize(sourceBean); //序列化的时候带着class字段,反序列化的时候就不需要指定目标class了。 System.out.println( "java
-> json:"
+ jsonStr); //
json -> java JSONDeserializer
deserializer = new
JSONDeserializer(); Classes
targetBean = (Classes) deserializer.deserialize(jsonStr); System.out.println( "json
-> java:"
+ BeanUtils.describe(targetBean) ); assertEquals(targetBean.getStudents().get( 0 ).getName(),
"张扇风" ); |
4、fastjson
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
package
com.zt.test; import
junit.framework.TestCase; import
com.alibaba.fastjson.JSON; public
class
FastJsonTest extends
TestCase{ public
void
testFastJson() throws
Exception { Classes
sourceBean = TestCommon.getTestBean(); //
java -> json String
json = JSON.toJSONString(sourceBean); //
System.out.println(json); //
json -> java Classes
targetBean = JSON.parseObject(json, Classes. class ); //
System.out.println(BeanUtils.describe(targetBean)); assertEquals(targetBean.getStudents().get( 0 ).getName(),
"张扇风" ); assertEquals(targetBean.getStudents().get( 0 ).getBirthday(),
TestCommon.DATEFORMAT.parse( "1800-01-01
01:00:00" )); } public
void
testLoad() throws
Exception { for
( int
i = 0 ;
i < 100000 ;
i++) { testFastJson(); } } } |
5、Jackson
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
package
com.zt.test; import
junit.framework.TestCase; import
com.fasterxml.jackson.databind.ObjectMapper; public
class
JacksonTest extends
TestCase{ public
void
testJackson() throws
Exception { Classes
sourceBean = TestCommon.getTestBean(); //
java -> json ObjectMapper
mapper = new
ObjectMapper(); //
can reuse, share globally String
json = mapper.writeValueAsString(sourceBean); //
System.out.println(json); //
json -> java Classes
targetBean = mapper.readValue(json, Classes. class ); //
System.out.println(BeanUtils.describe(targetBean)); assertEquals(targetBean.getStudents().get( 0 ).getName(),
"张扇风" ); assertEquals(targetBean.getStudents().get( 0 ).getBirthday(),
TestCommon.DATEFORMAT.parse( "1800-01-01
01:00:00" )); } public
void
testLoad() throws
Exception { for
( int
i = 0 ;
i < 100000 ;
i++) { testJackson(); } } } |
对比结果:
依赖jar个数 | 上手容易度 | 功能、特性 | 性能 | ||
json-lib | 5 | 难 |
java <-> json、xml<->json; 自定义格式; 属性过滤; |
25s | |
gson | 1 | 易 | java <-> json (待补充) | 15s | |
flexjson | 1 | 易 | java <-> json(待补充) | 12s | |
fastjson | 1 | 易 | java <-> json(待补充) | 3s | |
jackson | 1 | 易 | java <-> json(待补充) | 87s | |
性能测试:单个用例测试10W次java-json互转,测试多次取均速,测试非严格,只看相对性能就好,如果对测试结果有疑问的可以自己下载源码测试 |