json-lib(ezmorph)、gson、flexJson、fastjson、jackson对比,实现java转json,json转java

本文中所讲的所有代码都在此:json-test

目前关于java与json互转的工具包有很多 ,主流的主要有以下几个 :

  1. json-lib  (依赖于 ezmorph、commons-beanutils、commons-collections、groovy-all、oro、xom)
  2. gson
  3. flexjson
  4. fastjson
  5. 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互转,测试多次取均速,测试非严格,只看相对性能就好,如果对测试结果有疑问的可以自己下载源码测试

posted on 2014-06-06 17:59  分布式编程  阅读(170)  评论(0编辑  收藏  举报

导航