Part 1.反序列化部分
还是从part0那个json串入手,看看Fastjson框架是怎么把他拆出来的。
1.1 Fastjson中存取JSON对象的方法
首先,Fastjson是用JSONObject和JSONArray这两个类分别描述json对象和json数组的。那么先把这两个类拆开来看看。
1.1.1 JSONObject
通过阅读json文档得知,一个object由若干个(可以是0个)键值对组成,其中键是字符串(string),值可以是string,number,object,array,boolean,null这几种情况。那么这种数据结构在Java中对应了什么呢?
没错就是Map啊!~~
所以JSONObject封装了一个private final Map<String, Object> map;
,那么这个map是什么map呢?这取决于构造器了,默认的构造器是:
public JSONObject(){
this(DEFAULT_INITIAL_CAPACITY, false);
}
第一个参数代表初始容量,程序设定为16,第二个参数代表是否有序,默认为false。
如果有序,则用LinkedHashMap实现,否则用HashMap实现。
既然这样,那么JSON对象的key就不可以是重复的~~之前拆的cJSON是可以重复的,个人感觉就不对了。因为json文档中说
An object is an unordered set of name/value pairs.
既然是set,就不能重复的吧。。。
这个类的方法都比较简单,大多是HashMap的封装,get和set这种的。首先是各种根据key取对象的方法,有取Object的,取Array的,取JavaBean的等等。
public JSONObject getJSONObject(String key) {
Object value = map.get(key);
if (value instanceof JSONObject) {
return (JSONObject) value;
}
if (value instanceof String) {
return JSON.parseObject((String) value);
}
return (JSONObject) toJSON(value);
}
取对象的逻辑很简单,就是如果他是对应的对象,则直接取出来,如果是字符串,则parse成对象,否则转换成JSONObject(如果是JavaBean)。
此外,该框架还支持直接取日期、取时间戳、取BigInteger等封装好的方法,在底层均是调用了com.alibaba.fastjson.util包里的工具方法,在此先不分析。
然后添加元素方面呢,有一个比较有意思的fluentPut:
public JSONObject fluentPut(String key, Object value) {
map.put(key, value);
return this;
}
因为他返回的是this,所以就可以在一行代码里连续加入多个元素:(记得以前看php的时候看到连续调用觉得特别方便,其实实现原理都是一样的。)
myObj.fluentPut("key1",value1).fluentPut("key2",value2);
1.1.2 JSONArray
JSONArray和JSONObject差不多,就是底层结构换成了ArrayList。
1.1.3 TypeUtils工具包中直接取特殊类型的方法
前面说过,这个框架支持将json中的value直接转换成各种数字类、高精度、日期、时间戳等数据结构,都是在TypeUtils包中的castToxxx方法实现的。
- 基本类型
castToString、Byte、Char、Short、BigInteger、BigDecimal、Float、Double等都比较简单,主要就是特殊处理了value为”“,”NULL”,”null”三种情况,如果处理不了,就抛出JSONException异常。
- Date
关键是Date,可见该框架支持了很多很多日期类型,首先调用了词法分析器JSONScanner,先检测是否符合ISO 8601标准,再检测是否是”yyyy-MM-dd HH:mm:ss”,”yyyy-MM-dd”,”yyyy-MM-dd HH:mm:ss.SSS”等形式。
else if (strVal.length() == 10) {
format = "yyyy-MM-dd";
} else if (strVal.length() == "yyyy-MM-dd HH:mm:ss".length()) {
format = "yyyy-MM-dd HH:mm:ss";
}
顺便说下,这两句话风格统一下好不好。。。。
最后如果都不是,则看是不是时间戳,如果是时间戳则转换为对应的日期。
* JavaBean
还有一种特殊情况,就是取指定类,这个就比较麻烦了,如果是一些简单类如Integer,Float等直接调用相关方法即可,或者value存的就是你指定的类,都比较简单。
最复杂的情况就是,JSONObject里面存的是一个Map,而要取出的是这个Map对应的Bean。这个逻辑在方法castToJavaBean里实现。
1.2 输入字符串的反序列化
反序列化分为两部分,一是转换为JSON对象,二是转换为JavaBean。