json - downgoon/hello-world GitHub Wiki

问题列表

问题-1: 序列化与反序列化

假设有个City对象,需要序列化和反序列化:

public class City {
	private String name;
	private Integer gdp;
}

序列化相对简单,把对象弄成{'name': 'wangyi', 'gdp': 1867 }就好了。

但是反序列化,它怎么知道序列化成哪个类呢? 答案:反序列化时,需要在输入参数指定Class类型,比如Jackson2的做法是objectMapper.readValue(byte[] , City.class)

问题-2: JSON 编辑

构造一个JSON对象或数组,并对它进行:增、删、改和查。大多数情况,我们是“查”,编辑(增、删和改)涉及比较少。

假设父JSON是:P, 子JSON是S0和S1,其中S0是P已有的,S1是新加入的P的。伪代码表示:

S0 = P.get(0);
P.add(S1);

测试点:

  • 修改S0的属性取值,观察P对象是否发生变化?
  • 修改S1的属性取值,观察P对象是否发生变化?

实验-2:JSON编辑

进入测试代码

$ git checkout json
$ git checkout json-c1-updateproblem

json-lib 测试

代码UpdateProblemJsonlib.java:

public static void jsonUpdate(String[] args) throws Exception {

		String originJsonText = "[{\"name\": \"jinan\", \"gdp\": 123},{\"name\": \"qingdao\", \"gdp\": 456}]";
		JSONArray citiesJsonArray = JSONArray.fromObject(originJsonText);

        // get 浅拷贝(共享)
		JSONObject jinanJson = citiesJsonArray.getJSONObject(0); 
		System.out.println("jinan origin << " + jinanJson);
		System.out.println("cities origin << " + citiesJsonArray);

		System.out.println();
		jinanJson.element("gdp", "321");
		System.out.println("jinan changed >> " + jinanJson);
		System.out.println("cities changed ? >> " + citiesJsonArray); // true

        // add 深拷贝(复制)
		System.out.println();
		JSONObject hezeJson = JSONObject.fromObject("{\"name\": \"heze\", \"gdp\": 789}");
		citiesJsonArray.add(hezeJson); 
		System.out.println("cities after heze added >> " + citiesJsonArray);

		System.out.println();
		hezeJson.element("gdp", 987);
		System.out.println("heze updated >> " + hezeJson);
		System.out.println("cities after heze updated ? >> " + citiesJsonArray); // false

		// [{"name":"jinan","gdp":"321"},{"name":"qingdao","gdp":456},{"name":"heze","gdp":789}]
		// heze 数据依然是 789,并没有发生变化。这种特性跟JAVA对象是不一样的。
	}

上述代码对一个JSONArray,取出第一个对象,假设S0;加入了新对象,假设S1。并分别对S0和S1的属性取值做更新,观察JSONArray是否也发生变化,以便判断“浅拷贝(共享模式)”还是“深拷贝(复制模式)”。

jinan origin << {"name":"jinan","gdp":123}
cities origin << [{"name":"jinan","gdp":123},{"name":"qingdao","gdp":456}]
jinan changed >> {"name":"jinan","gdp":"321"}
cities changed ? >> [{"name":"jinan","gdp":"321"},{"name":"qingdao","gdp":456}]
cities after heze added >> [{"name":"jinan","gdp":"321"},{"name":"qingdao","gdp":456},{"name":"heze","gdp":789}]
heze updated >> {"name":"heze","gdp":987}
cities after heze updated ? >> [{"name":"jinan","gdp":"321"},{"name":"qingdao","gdp":456},{"name":"heze","gdp":789}]

heze updated >> {"name":"heze","gdp":987}

新加入的对象S1更新后,对应的JSONArray并不会更新。

jackson2 测试

代码UpdateProblemJackson2.java

public static void jsonUpdate() throws Exception {

		String originJsonText = "[{\"name\": \"jinan\", \"gdp\": 123},{\"name\": \"qingdao\", \"gdp\": 456}]";
		
		ObjectMapper mapper = new ObjectMapper();
		
		// JSONArray citiesJsonArray = JSONArray.fromObject(originJsonText);
		ArrayNode citiesJsonArray = mapper.readValue(originJsonText.getBytes(), ArrayNode.class);

		// JSONObject jinanJson = citiesJsonArray.getJSONObject(0); // get 浅拷贝(共享)
		ObjectNode jinanJson = (ObjectNode) citiesJsonArray.get(0);
		
		System.out.println("jinan origin << " + jinanJson);
		System.out.println("cities origin << " + citiesJsonArray);

		System.out.println();
		// jinanJson.element("gdp", "321");
		jinanJson.put("gdp", 321);
		
		System.out.println("jinan changed >> " + jinanJson);
		System.out.println("cities changed ? >> " + citiesJsonArray); // true

		System.out.println();
		// JSONObject hezeJson = JSONObject.fromObject("{\"name\": \"heze\", \"gdp\": 789}");
		ObjectNode hezeJson = mapper.readValue("{\"name\": \"heze\", \"gdp\": 789}", ObjectNode.class);
		
		citiesJsonArray.add(hezeJson); // add 深拷贝(复制)
		System.out.println("cities after heze added >> " + citiesJsonArray);

		System.out.println();
		// hezeJson.element("gdp", 987);
		hezeJson.put("gdp", 987);
		
		System.out.println("heze updated >> " + hezeJson);
		System.out.println("cities after heze updated ? >> " + citiesJsonArray); // false

		// [{"name":"jinan","gdp":"321"},{"name":"qingdao","gdp":456},{"name":"heze","gdp":789}]
		// heze 数据依然是 789,并没有发生变化。这种特性跟JAVA对象是不一样的。
	}

运行结果:

jinan origin << {"name":"jinan","gdp":123}
cities origin << [{"name":"jinan","gdp":123},{"name":"qingdao","gdp":456}]

jinan changed >> {"name":"jinan","gdp":321}
cities changed ? >> [{"name":"jinan","gdp":321},{"name":"qingdao","gdp":456}]

cities after heze added >> [{"name":"jinan","gdp":321},{"name":"qingdao","gdp":456},{"name":"heze","gdp":789}]

heze updated >> {"name":"heze","gdp":987}
cities after heze updated ? >> [{"name":"jinan","gdp":321},{"name":"qingdao","gdp":456},{"name":"heze","gdp":987}]

发现当"heze"城市的gdb更新后,无论是heze对象,还是JSONArray,都更新了。这个行为跟json-lib不一样,但jackson2更符合大家预期。

fastjson 测试

进入代码:

$ git checkout json
$ git checkout json-c2-fastjson

查看代码:UpdateProblemFastjson.java

	public static void main(String[] args) throws Exception {

		String originJsonText = "[{\"name\": \"jinan\", \"gdp\": 123},{\"name\": \"qingdao\", \"gdp\": 456}]";
		JSONArray citiesJsonArray =  JSON.parseArray(originJsonText);
		

		JSONObject jinanJson = citiesJsonArray.getJSONObject(0); // get 浅拷贝(共享)
		System.out.println("jinan origin << " + jinanJson);
		System.out.println("cities origin << " + citiesJsonArray);

		System.out.println();
		jinanJson.put("gdp", 321);
		System.out.println("jinan changed >> " + jinanJson);
		System.out.println("cities changed ? >> " + citiesJsonArray); // true

		System.out.println();
		JSONObject hezeJson = JSON.parseObject("{\"name\": \"heze\", \"gdp\": 789}");
		citiesJsonArray.add(hezeJson); // add 深拷贝(复制)
		System.out.println("cities after heze added >> " + citiesJsonArray);

		System.out.println();
		hezeJson.put("gdp", 987);
		
		System.out.println("heze updated >> " + hezeJson);
		System.out.println("cities after heze updated ? >> " + citiesJsonArray); // false

	}

运行结果:

heze updated >> {"gdp":987,"name":"heze"}
cities after heze updated ? >> [{"gdp":321,"name":"jinan"},{"gdp":456,"name":"qingdao"},{"gdp":987,"name":"heze"}]

fastjson 真心很赞:

  • 命名上,跟json-lib很易懂。
  • 行为上,跟jackson一致。

此外,fastjson还解决了非常多的问题,都在FAQ列出来了。其中还包括兼容IE6下JSON不支持中文(JSON中含中文的需要转化成Unicode编码)。

关于 fastjson 的性能:

fastjson的性能如何?

fastjson是目前java语言中最快的json库,比自称最快的jackson速度要快,第三方独立测试结果看这里:https://github.com/eishay/jvm-serializers/wiki/Staging-Results

自行做性能测试时,关闭循环引用检测的功能。

JSON.toJSONString(obj, SerializerFeature.DisableCircularReferenceDetect) VO vo = JSON.parseObject("...", VO.class, Feature.DisableCircularReferenceDetect)


>这里有jackson作者cowtowncoder等人对fastjson的性能评价: https://groups.google.com/forum/#!topic/java-serialization-benchmarking/8eS1KOquAhw


# 结论

- 两个关注的json: 关注阿里的 fastjson 和 spring默认的jackson (功能丰富) 即可。
- 两个落后的json: gson 和 json-lib 都很落后了。