Gson源码解析
简介
Gson 是一个 Java 库,可用于将 Java 对象转换为其 JSON 表示形式。它还可用于将 JSON 字符串转换为等效的 Java 对象。
地址https://github.com/google/gson
1 | dependencies { |
简单使用
1 | public class Person { |
1 | public class JsonTest { |
源码分析
构造方法
无参构造器
1 | public Gson() { |
有参构造器
1 | Gson(Excluder excluder, FieldNamingStrategy fieldNamingStrategy, |
GsonBuilder
1 | Gson gson = new GsonBuilder() |
TypeAdapter
TypeAdapter是Gson的核心,它的设计是一个适配器模式
因为Json数据接口和Type的接口两者是无法兼容,因此TypeAdapter就是来实现兼容,把json数据读到Type中,把Type中的数据写入到Json里。
1 | public abstract class TypeAdapter<T> { |
Gson会为每一种类型创建一个TypeAdapter,同样的,每一个Type都对应唯一一个TypeAdapter
而所有Type(类型),在Gson中又可以分为基本类型和复合类型(非基本类型)
基本类型(Integer,String,Uri,Url,Calendar…)
复合类型(非基本类型):即除了基本类型之外的类型
流程简图
TypeAdapterFactory
在 Gson 中封装了不同类型的读写的业务组装类是各个 TypeAdapter(适配器)
1 | public interface TypeAdapterFactory { |
如何获取TypeAdapter
1 | TypeAdapter<?> cached = typeTokenCache.get(type == null ? NULL_KEY_SURROGATE : type); |
从缓存获取TypeAdapter对象,存在者直接返回
1 | FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type); |
通过ThreadLocal缓存TypeAdapter对象,不同的线程使用缓存来解析的时候互不影响。
1 | for (TypeAdapterFactory factory : factories) { |
如果不存在缓存,那么从factories列表里查找,factories是在创建Gson对象时初始化,添加了很多用于创建TypeAdapter对象的TypeAdapterFactory。
JsonReader/JsonWriter
在Gson中,Java对象与JSON字符串之间的转换是通过字符流来进行操作的。JsonReader继承于Reader用来读取字符,JsonWriter继承于Writer用来写入字符。
JsonReader
进行数据的写入 用于反序列化操作
- beginObject():将状态数组的状态的第一个位置从EMPTY_DOCUMENT变为NONEMPTY_DOCUMENT,然后将第二个位置变为EMPTY_OBJECT
- beginArray():将状态数组的状态的第一个位置从EMPTY_DOCUMENT变为NONEMPTY_DOCUMENT,然后将第二个位置变为EMPTY_OBJECT
- endObject :将peek设置为peek_none;将pathNames数组中stackSize位置设置为null
- endArray:将peek设置为peek_none;将pathNames数组中stackSize位置设置为null
- hasNext:通过标识符判断是否还有数据可以读取
- nextName:获取json中对应的key值
- nextString:获取json中对应的String类型的value值
- nextBoolean:获取json中对应的Boolean类型的value值
- nextDouble:获取json中对应的Double类型的value值
- nextLong:获取json中对应的Long类型的value值
- nextInt:获取json中对应的Int类型的value值
- nextUnquotedValue:以字符串形式返回未加引号的值
- nextQuotedValue:以字符串形式返回加引号的值
- peek:根据peek当前的的状态,判断下一个状态是什么
- close():关闭输入流
JsonWriter
- beginObject:通过open()写入json是object的起始符号**{**,在写入数据之前需要调用该方法
- endObject:通过clase()写入json是object的结束符号**}** 在写入数据结束后需要调用该方法
- beginArray:通过open()写入json是array的起始符号**[**,在写入数据之前需要调用该方法
- endArray:通过close()写入json是array的结束符号**]**,在数据结束后需要调用该方法
- name:设置deferredName
- writeDeferredName:通过Writer将deferredName值写入
- value:首先判断是否是第一个数据,若不是则需要先写入逗号(,),然后写入deferredName值,之后写入分号(:),最后写入value值
- nullValue: 写入null
JsonElement
该类是一个抽象类,代表着json串的某一个元素。这个元素可以是一个Json(JsonObject)、可以是一个数组(JsonArray)、可以是一个Java的基本类(JsonPrimitive)、当然也可以为null(JsonNull);JsonObject,JsonArray,JsonPrimitive,JsonNull都是JsonElement这个抽象类的子类。JsonElement提供了一系列的方法来判断当前的JsonElement。
各个JsonElement的关系可以用如下图表示:
JsonObject对象可以看成 name/values的集合,而这写values就是一个个JsonElement,他们的结构可以
用如下图表示:
Gson整体解析原理
- Gson将使用者传入的字符串或对象存入读取器(JsonReader)或者写入器(JsonWriter)中
- Gson遍历并获取能够处理对应类型的适配器工厂(TypeAdapterFactory)
- 适配器工厂TypeAdapterFactory会创建出对应类型的适配器(TypeAdapter)
- Gson将阅读器JsonReader或写入器JsonWriter交给适配器
- 适配器自行通过业务逻辑操作读取器JsonReader或写入器JsonWriter,输出需要的结果
- Gson接收此输出,并交给使用者
Gson反射解析机制
Gson解析常见的错误
Expected BEGIN_ARRAY but was STRING at line 1 column 27
这种错误一般都是原来是一个字段需要是数组类型,但是事实上给的是””,导致的
解决办法
让返回null即可解决问题
用Gson自带的解决方案
1 | static class GsonError1Deserializer implements JsonDeserializer<GsonError1> { |
1 | public static void test3() { |