源码介绍
Fastjson 是阿里巴巴开源的一个 Java 工具库,它常常被用来完成 Java 的对象与 JSON 格式的字符串的相互转化。
此文读的源码是撰写此文时 Fastjson 的最新的发布版本,即 1.2.83
下载源码
请前去 github 找到 release 最新版下载后解压,地址为:https://github.com/alibaba/fastjson/releases/tag/1.2.83
项目结构
使用 IDEA 打开 fastjson-1.2.83
文件夹,下载相关依赖后,我们再开始阅读源码,接下来我们分别对 JSON
、JSONArray
与 JSONObject
。
JSON 实现两个接口
JSON 类是实现两个接口 JSONStreamAware
、JSONAware
的抽象类,即
public abstract class JSON implements JSONStreamAware, JSONAware
我们先介绍这两个接口:
JSONStreamAware
方法 writeJSONString
中的参数 Appendable
也是一个接口,也就是可以附加字符序列和值的对象,这个接口的作用是提供一个输出JSON字符串的方法,以便于其他的方法调用。
接着我们在 JSON
抽象类中寻找用到这个方法的地方,这里主要截图其中两个具体的实现方法,另外还有几个重载方法是通过调用这两个方法的方法,这里不再列举。
JSONAware
这个接口更加简单了,实现该接口的类即需要实现 toJSONString 的方法即可。
在JSON抽象类中,具体实现为:
这里调用的是 JSONSerializer
类的对象方法,这里我们在后面介绍这个类的时候进一步介绍。
这个相对于 writeJSONString
更加实用。比如重写 toString
方法。
JSON 类的静态方法
我们常常用到这些方法,并且我们在使用 JSONObject 类方法的时候也经常用得到(JSONObject是JSON类的子类)。这里我们介绍我们最最最常用的,并且在 JSONObject 中不再介绍。
JSON.toString / JSON.toJSONString
这个方法前面关于 JSONAware 接口的实现的时候有提到过,这里就不做介绍了。
这里我们看一下 toJSONString 方法的实现原理。源码比较简单,这里就不逐行介绍了。
方法参数介绍
- object: Object 待转换的 Java 对象;
- defaultFeatures: int 后面参数 SerializerFeature 的长度,因为后面是
SerializerFeature...
类型的,所以调用时需要指定它的长度; - features: SerializerFeature… 这个地方是指多个 SerializerFeature 类型的对象,调用时可以
toJSONString(obj, 1, feature0)
也可以toJSONString(obj, 2, feature0, feature1)
,也可以toJSONString(obj, 3, feature0, feature1, feature2)
等等。
/*** @since 1.2.11*/public static String toJSONString(Object object, int defaultFeatures, SerializerFeature... features) {SerializeWriter out = new SerializeWriter((Writer) null, defaultFeatures, features);try {JSONSerializer serializer = new JSONSerializer(out);serializer.write(object);String outString = out.toString();int len = outString.length();if (len > 0&& outString.charAt(len -1) == '.'&& object instanceof Number&& !out.isEnabled(SerializerFeature.WriteClassName)) {return outString.substring(0, len - 1);}return outString;} finally {out.close();}}
源码中用到了 SerializeWriter 对象以及它的方法,这里我们理一下它的作用与用法。
SerializeWriter 构造函数为
public SerializeWriter(Writer writer, int defaultFeatures, SerializerFeature... features){this.writer = writer;buf = bufLocal.get();if (buf != null) {bufLocal.set(null);} else {buf = new char[2048];}int featuresValue = defaultFeatures;for (SerializerFeature feature : features) {featuresValue |= feature.getMask();}this.features = featuresValue;computeFeatures();}
在前面初始化JSONSerializer的时候调用SerializeWriter对象,即 JSONSerializer serializer = new JSONSerializer(out);
这个时候的使用方法是:
这里查看 JSONSerializer
对象的构造函数:
public JSONSerializer(SerializeWriter out){this(out, SerializeConfig.getGlobalInstance());}public JSONSerializer(SerializeWriter out, SerializeConfig config){this.out = out;this.config = config;}
其 write 方法源码为:
public final void write(Object object) {if (object == null) {out.writeNull();return;}Class<?> clazz = object.getClass();ObjectSerializer writer = getObjectWriter(clazz);try {writer.write(this, object, null, null, 0);} catch (IOException e) {throw new JSONException(e.getMessage(), e);}}
JSONObject
相对而言 JSONObject 用得更多,这里需要介绍的也更多。
无参构造函数
其中 DEFAULT_INITIAL_CAPACITY
默认等于 16,也就是创建 HashMap 或者 LinkedHashMap 对象的时候默认的 initialCapacity 的值,而 order 参数将会指定创建的 map 对象的类型。
public JSONObject(){this(DEFAULT_INITIAL_CAPACITY, false);}public JSONObject(int initialCapacity, boolean ordered){if (ordered) {map = new LinkedHashMap<String, Object>(initialCapacity);} else {map = new HashMap<String, Object>(initialCapacity);}}public JSONObject(boolean ordered){this(DEFAULT_INITIAL_CAPACITY, ordered);}public JSONObject(int initialCapacity){this(initialCapacity, false);}
有参构函数
public JSONObject(Map<String, Object> map){if (map == null) {throw new IllegalArgumentException("map is null.");}this.map = map;}
这里相对于前面的无参构造函数而言,map
对象在外界创建与初始化,直接传入 JSONObject 中,作为构造函数。这样做使得我们在反序列化、序列化的方法更加灵活,这里我们在后面介绍。
containsKey / containsValue / get / isEmpty / size 方法
这几个方法都是直接调用 成员变量 map
得以实现的,具体实现代码如下:
public int size() {return map.size();}public boolean isEmpty() {return map.isEmpty();}public boolean containsKey(Object key) {boolean result = map.containsKey(key);if (!result) {if (key instanceof Number|| key instanceof Character|| key instanceof Boolean|| key instanceof UUID) {result = map.containsKey(key.toString());}}return result;}public boolean containsValue(Object value) {return map.containsValue(value);}public Object get(Object key) {Object val = map.get(key);if (val == null) {if (key instanceof Number|| key instanceof Character|| key instanceof Boolean|| key instanceof UUID) {val = map.get(key.toString());}}return val;}public Object getOrDefault(Object key, Object defaultValue) {Object v;return ((v = get(key)) != null) ? v : defaultValue;}
反序列化方法
首先出场的是最简单的,将 map 中的某个 key 进行反序列化,一般情况下我们会在 这个 key 对应的是 Object 的时候使用它。比如原始的map 是 {"age": 3, "item" : {"color": "black", "length" : 2}}
,我们在反序列化 item
的时候需要调用这个方法,即 getJSONObject("item")
。
public JSONObject getJSONObject(String key) {Object value = map.get(key);if (value instanceof JSONObject) {return (JSONObject) value;}if (value instanceof Map) {return new JSONObject((Map) value);}if (value instanceof String) {return JSON.parseObject((String) value);}return (JSONObject) toJSON(value);}
类似地如果是 JSON 数组的化,调用 getJSONArray
方法,这里举一个例子为 map
为 {"age": 3, items:[{"color": "red"}, {"color": "black"}]}
,我们在反序列 items 的时候会调用这个方法。
public JSONArray getJSONArray(String key) {Object value = map.get(key);if (value instanceof JSONArray) {return (JSONArray) value;}if (value instanceof List) {return new JSONArray((List) value);}if (value instanceof String) {return (JSONArray) JSON.parse((String) value);}return (JSONArray) toJSON(value);}
如果不是前面两种,我们需要获取的只是简单的 item
对象,比如 age = 3
,那么就调用 getObject
方法即可,注意这里有几个重载方法。
public <T> T getObject(String key, Class<T> clazz) {Object obj = map.get(key);return TypeUtils.castToJavaBean(obj, clazz);}public <T> T getObject(String key, Type type) {Object obj = map.get(key);return TypeUtils.cast(obj, type, ParserConfig.getGlobalInstance());}public <T> T getObject(String key, TypeReference typeReference) {Object obj = map.get(key);if (typeReference == null) {return (T) obj;}return TypeUtils.cast(obj, typeReference.getType(), ParserConfig.getGlobalInstance());}
这个时候我们不得不介绍一下 TypeUtils
类了,毕竟出场率这么高,这里只介绍 cast
与 castToJavaBean
两个静态方法。
private static BiFunction<Object, Class, Object> castFunction = new BiFunction<Object, Class, Object>() {public Object apply(Object obj, Class clazz) {if (clazz == java.sql.Date.class) {return castToSqlDate(obj);}if (clazz == java.sql.Time.class) {return castToSqlTime(obj);}if (clazz == java.sql.Timestamp.class) {return castToTimestamp(obj);}return null;}};
这里实现了接口 BiFunction 的 apply 方法,实现方法也非常简单粗暴,三个 if 对应三个方法 castToSql / castToSqlTime / castToTimestamp 。
这个时候可能大家会疑惑,这个跟 sql 有什么关系?其实确实没什么关系,但是毕竟 java 提供的现有的可用方法,不用白不用,这里也给大家做个广告,这里面的 java.sql.Timestamp
与 java.sql.Time
以及 java.sql.Date
确实很好用,这里以 java.sql.Timestamp
为例,它提供13位时间戳的构造方法 public Timestamp(long time)
以及常用的 compareTo
、before
、after
方法,需要的小伙伴可以自取使用。
而 cast
方法 居然都有 @SuppressWarnings("unchecked")
标注,着实让人多少有点不放心,难道一定要去使用 Fastjson2 ?
这里我们查看其中一个方法的实现,看完了你大概就会产生一种 “就这?我上我也行” 的感觉:
@SuppressWarnings("unchecked")public static <T> T cast(Object obj, Type type, ParserConfig mapping) {if (obj == null) {return null;}if (type instanceof Class) {return cast(obj, (Class<T>) type, mapping);}if (type instanceof ParameterizedType) {return (T) cast(obj, (ParameterizedType) type, mapping);}if (obj instanceof String) {String strVal = (String) obj;if (strVal.length() == 0 //|| "null".equals(strVal) //|| "NULL".equals(strVal)) {return null;}}if (type instanceof TypeVariable) {return (T) obj;}throw new JSONException("can not cast to : " + type);}
事实也确实如此,充其量就是用了点反射技术,首先判断数据类型属于哪个小可爱的子类,然后再使用放射和传过来的 clazz 创建对象,而建立其中的映射关系的,就是其中的 mapping
参数对象,仅此而已。
JSON 与 JSONObject 的区别与联系
能够用 JSON 的地方,基本上都能用 JSONObject,不同之处在于一般直接 JSON 的静态方法,因为它是抽象类,不能直接 new 出对象的。而 JSONObject 名字中就强调了 Object 的概念,所以一般直接就用它的对象的方法。
灵活使用 JSONObject
总体来说最经常用到的就是 toString 与 toJSONObject 以及 JSONObject 对象的 getInteger / getLong / getJSONObject 等等方法,这些方法都应该基于 map 联想记忆,都是比较容易理解的。
总结
Fastjson 中存在很多地方都属于让人看了就 “恍然大悟” 之处,也推荐大家去阅读,同时不得不说,阿里巴巴能够有支团队开发并不断完善Fastjson,也是挺值得前去 github 点颗星星。
最后吐槽一下 Fastjson 的实现部分有明显的 “不遵守 《JAVA 规范手册》” 的,请以后的开发人员注意多多参考 Java开发手册(嵩山版) ,多写一些些注释,成为一本与 手册 配套的代码示例,也是非常不错的 ~ 此致,敬上 ~
Smileyan
2023.04.13 00:44