1、JSON 解析基础知识
JSON 实际上就是个字符串,解析 JSON 就是将 JSON 中的数据结构化的对应到语言本身的数据结构中。编写一个 JSON 解析器实际上就是一个方法,输入一个 JSON 字符串,输出一个对应语言的数据结构。一般来说,解析过程包括两个阶段:
- 词法分析:根据构词规则对 JSON 字符串进行解析,得到一组 Token 序列
- 语法分析:根据 JSON 语法检查上面的 Token 序列所构成的 JSON 结构是否合法
词法分析时会关注 JSON 所定义的数据类型:
- BEGIN_OBJECT({)
- END_OBJECT(})
- BEGIN_ARRAY([)
- END_ARRAY(])
- NULL(null)
- NUMBER(数字)
- STRING(字符串)
- BOOLEAN(true/false)
- SEP_COLON(:)
- SEP_COMMA(,)
语法分析则会根据 Token 中每个词的第一个字符判断出该词的 Token Type:
- n ➔ null
- t ➔ true
- f ➔ false
- " ➔ string
- 0-9/- ➔ number
- [ ➔ array
- { ➔ object
语法分析后得到一个 JSONObject,对于 Java 来说,此时需要将其转换成一个 JavaBean,大致步骤为:
- 反射创建 value 对应类型的对象
- 把 JSON 中对应的值赋给对象对应的属性
- 返回该对象
最后说下常用的 JSON 解析方式,有两种:
- 文档驱动型:一次性读取整个文档中的 JSON 字符串进入内存,再进行词法分析和语法分析。只适合数据量不大时使用,JSON 数据过大时可能会撑爆内存。
- 事件驱动型:边加载、边解析。比如加载到一个 { 会认为是一个对象的开始,后续预期读入一个 key 的 ",如果不是则报错,如果是,则更新预期并继续读入新字符,直到文档结束。效率相比于文档驱动要低一些,但是数据量大时不会过多的占用内存。
我们要介绍的 Gson 就是事件驱动型解析器。
2、Gson 类介绍
2.1 基础类
JsonToken
JsonToken 对应词法规则:
/**
* A structure, name or value type in a JSON-encoded string.
*
* @author Jesse Wilson
* @since 1.6
*/
public enum JsonToken {
/**
* The opening of a JSON array. Written using {@link JsonWriter#beginArray}
* and read using {@link JsonReader#beginArray}.
*/
BEGIN_ARRAY,
/**
* The closing of a JSON array. Written using {@link JsonWriter#endArray}
* and read using {@link JsonReader#endArray}.
*/
END_ARRAY,
/**
* The opening of a JSON object. Written using {@link JsonWriter#beginObject}
* and read using {@link JsonReader#beginObject}.
*/
BEGIN_OBJECT,
/**
* The closing of a JSON object. Written using {@link JsonWriter#endObject}
* and read using {@link JsonReader#endObject}.
*/
END_OBJECT,
/**
* A JSON property name. Within objects, tokens alternate between names and
* their values. Written using {@link JsonWriter#name} and read using {@link
* JsonReader#nextName}
*/
NAME,
/**
* A JSON string.
*/
STRING,
/**
* A JSON number represented in this API by a Java {@code double}, {@code
* long}, or {@code int}.
*/
NUMBER,
/**
* A JSON {@code true} or {@code false}.
*/
BOOLEAN,
/**
* A JSON {@code null}.
*/
NULL,
/**
* The end of the JSON stream. This sentinel value is returned by {@link
* JsonReader#peek()} to signal that the JSON-encoded value has no more
* tokens.
*/
END_DOCUMENT
}
JsonScope
JsonScope 定义了表示 JSON 作用域的元素:
/**
* Lexical scoping elements within a JSON reader or writer.
*
* @author Jesse Wilson
* @since 1.6
*/
final class JsonScope {
/**
* An array with no elements requires no separators or newlines before
* it is closed.
*/
static final int EMPTY_ARRAY = 1;
/**
* A array with at least one value requires a comma and newline before
* the next element.
*/
static final int NONEMPTY_ARRAY = 2;
/**
* An object with no name/value pairs requires no separators or newlines
* before it is closed.
*/
static final int EMPTY_OBJECT = 3;
/**
* An object whose most recent element is a key. The next element must
* be a value.
*/
static final int DANGLING_NAME = 4;
/**
* An object with at least one name/value pair requires a comma and
* newline before the next element.
*/
static final int NONEMPTY_OBJECT = 5;
/**
* No object or array has been started.
*/
static final int EMPTY_DOCUMENT = 6;
/**
* A document with at an array or object.
*/
static final int NONEMPTY_DOCUMENT = 7;
/**
* A document that's been closed and cannot be accessed.
*/
static final int CLOSED = 8;
}
JsonElement
抽象类 JsonElement 表示 Json 中的一个元素,它可以是 JsonObject、JsonArray、JsonPrimitive 和 JsonNull 四个子类中的任意一个:
- JsonObject 表示一个对象类型。一个 JsonObject 包含一个 name-value 对,其中 name 是一个字符串,value 可以是 JsonElement 的任意一种。这样就允许创建一个 JsonElement 树。一个 JsonObject 的成员元素,是根据它们的添加顺序维护的。
- JsonArray 表示 Json 数组,数组中的元素类型可以不唯一,元素排列顺序按照元素添加顺序。
- JsonPrimitive 表示一个 Json 的原始值,可以是一个字符串,也可以是一个 Java 的基本类型及其包装类。
- JsonNull 表示一个 Json 数据的 null 值,除了 hashCode()、equals() 之外,仅支持 JsonElement 中的 deepCopy()。
JsonObject 的叶节点一定是一个基本类型 JsonPrimitive。
2.2 TypeAdapter 与适配器模式
适配器模式
适配器是将两个不兼容的类融合在一起,把一个类的接口变成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类可以在一起工作。它有以下三种使用场景:
1. 系统需要使用现有的类,而此类的接口不符合系统的需要,即接口不兼容。
2. 想要建立一个重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。
3. 需要一个统一的输出接口,而输入端的类型不可预知。
举个例子,我们日常使用的手机充电器就可以理解为是一种适配器模式的应用。电源的输入电压为220V,而手机的输入电压可能就只有5V,这时就需要充电器作为电源适配器对电压进行兼容性的改变。
在上面的例子中,其实有三个角色:
1. Target:目标角色,也就是期待得到的接口(5V电压)。它可以是具体类、抽象类,甚至是接口(注:类适配器模式只能是接口,对象适配器模式三者皆可)。
2. Adaptee:需要被适配的接口(220V电压)。
3. Adapter:适配器角色(电源适配器)。把源接口转换成目标接口。这个角色必须是具体类。
根据下面的适配器结构图可以发现,系统当前需要的是 Target 类的对象具有 Adaptee 类中 operation3() 的功能,那么就需要通过继承 Adaptee 或者持有 Adaptee 对象的形式能够拥有 operation3() 方法,然后在 Target 的 operation2() 中对其进行转换,适配成系统需要的方法内容。
根据适配器模式类型的不同,可以有如下两种结构图:
类适配器模式中,Adapter 通过继承 Adaptee 获得其方法,由于 Java 不支持多继承,因此 Target 只能是接口。
对象适配器模式中,Adapter 会持有 Adaptee 的一个对象,因此 Target 可以是接口、抽象类、具体类中的任意一种。比类适配器的方式更为灵活,并且被适配对象的方法不会暴露出来(类适配器继承了被适配的类,使得被适配类的方法也存在与 Adapter 中,提高了用户的使用成本),因此对象适配器较为常用。
适配器参考文章:
深入理解适配器模式
适配器模式
java/android 设计模式学习笔记(6)—适配器模式
TypeAdapter
TypeAdapter 就是适配了 JSON 和 Type:
TypeAdapter 是一个抽象类,有两个抽象方法 read() 和 write() 分别负责将 JSON 字符串反序列化成指定类型 T、将指定类型 T 的对象序列化成 JSON 字符串:
/**
* Writes one JSON value (an array, object, string, number, boolean or null)
* for {@code value}.
*
* @param value the Java object to write. May be null.
*/
public abstract void write(JsonWriter out, T value) throws IOException;
/**
* Reads one JSON value (an array, object, string, number, boolean or null)
* and converts it to a Java object. Returns the converted object.
*
* @return the converted Java object. May be null.
*/
public abstract T read(JsonReader in) throws IOException;
每种数据类型都对应有一种 TypeAdapter,如 TypeAdapter<String>、TypeAdapter<BigDecimal> 等,它们都被定义在工具类 TypeAdapters 中:
public static final TypeAdapter<String> STRING = new TypeAdapter<String>() {
@Override
public String read(JsonReader in) throws IOException {
JsonToken peek = in.peek();
if (peek == JsonToken.NULL) {
in.nextNull();
return null;
}
/* coerce booleans to strings for backwards compatibility */
if (peek == JsonToken.BOOLEAN) {
return Boolean.toString(in.nextBoolean());
}
return in.nextString();
}
@Override
public void write(JsonWriter out, String value) throws IOException {
out.value(value);
}
};
public static final TypeAdapter<BigDecimal> BIG_DECIMAL = new TypeAdapter<BigDecimal>() {
@Override
public BigDecimal read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
try {
return new BigDecimal(in.nextString());
} catch (NumberFormatException e) {
throw new JsonSyntaxException(e);
}
}
@Override
public void write(JsonWriter out, BigDecimal value) throws IOException {
out.value(value);
}
};
TypeAdapters 内虽然预定义了多种数据的 TypeAdapter,但是总归会有它处理不了的数据类型,此时需要我们自定义 TypeAdapter。如果没有自定义实现,Gson 会使用默认的解决方案,利用 ReflectiveTypeAdapterFactory.Adapter 通过反射实现读写 JSON。
ReflectiveTypeAdapterFactory 实现了 TypeAdapterFactory 接口,该接口只有一个方法用于创建 TypeAdapter 对象:
public interface TypeAdapterFactory {
/**
* Returns a type adapter for {@code type}, or null if this factory doesn't
* support {@code type}.
*/
<T> TypeAdapter<T> create(Gson gson, TypeToken<T> type);
}
T 的类型信息是通过参数中的 TypeToken 获取到的:
public class TypeToken<T> {
final Class<? super T> rawType; // 原始类型
final Type type; // 父类的类型参数
protected TypeToken() {
this.type = getSuperclassTypeParameter(getClass());
this.rawType = (Class<? super T>) $Gson$Types.getRawType(type);
this.hashCode = type.hashCode();
}
@SuppressWarnings("unchecked")
TypeToken(Type type) {
this.type = $Gson$Types.canonicalize($Gson$Preconditions.checkNotNull(type));
this.rawType = (Class<? super T>) $Gson$Types.getRawType(this.type);
this.hashCode = this.type.hashCode();
}
static Type getSuperclassTypeParameter(Class<?> subclass) {
Type superclass = subclass.getGenericSuperclass();
if (superclass instanceof Class) {
throw new RuntimeException("Missing type parameter.");
}
ParameterizedType parameterized = (ParameterizedType) superclass;
// 父类的第一个类型参数传入 $Gson$Types.canonicalize
return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
}
}
两个构造方法仅在为 G s o n Gson GsonTypes.canonicalize() 提供 Type 参数的方式上有区别,无参的 TypeToken() 是取 TypeToken 这个类的父类的类型参数作为 canonicalize() 的参数,而有参数的 TypeToken(Type type) 则直接用 type 传给 canonicalize()。
关于空参的 TypeToken() 为什么取父类的类型参数给成员变量 type,方法注释上写道:使用者创建一个空的匿名子类。这样做可以将类型参数嵌入到匿名类的类型层次结构中,这样即便泛型被擦除了也可以在运行时重建它。
在 TypeToken 的类上也有类似的注释:TypeToken<T> 表示了泛型 T。Java 还没有提供表示泛型类型的方法,所以这个类提供了。强制客户端创建该类的子类,以便在运行时也能检索类型信息。例如,要为 LIst<String> 创建一个类型表示,你可以创建一个空的匿名内部类:
TypeToken<List<String>> list = new TypeToken<List<String>>() {};
但是需要注意这种方法不能用于创建具有通配符的类型参数,如 Class<?> 或 List<? extends CharSequence>。
G s o n Gson GsonTypes.canonicalize(Type) 则会根据 Type 的真实类型返回对应的 Type 的实现类对象:
// 返回的 GenericArrayTypeImpl、ParameterizedTypeImpl、GenericArrayType 和
// WildcardTypeImpl 都是由 $Gson$Types 以内部类的形式实现的对应的 Type 的子接口
public static Type canonicalize(Type type) {
if (type instanceof Class) {
Class<?> c = (Class<?>) type;
return c.isArray() ? new GenericArrayTypeImpl(canonicalize(c.getComponentType())) : c;
} else if (type instanceof ParameterizedType) {
ParameterizedType p = (ParameterizedType) type;
return new ParameterizedTypeImpl(p.getOwnerType(),
p.getRawType(), p.getActualTypeArguments());
} else if (type instanceof GenericArrayType) {
GenericArrayType g = (GenericArrayType) type;
return new GenericArrayTypeImpl(g.getGenericComponentType());
} else if (type instanceof WildcardType) {
WildcardType w = (WildcardType) type;
return new WildcardTypeImpl(w.getUpperBounds(), w.getLowerBounds());
} else {
// type is either serializable as-is or unsupported
return type;
}
}
所以这样看下来,TypeToken 中的 type 字段,在使用匿名内部类的空参构造方法时,它就是 TypeToken<T> 的 T 这个类型,对应 Type 接口的 GenericArrayTypeImpl、ParameterizedTypeImpl、GenericArrayType 和 WildcardTypeImpl 四者之一。
3、解析流程
Gson 解析 JSON 的流程简图如下:
解析 JSON 字符串时,先对其类型 Type 进行判断,如果被解析元素是基本类型,就直接调用对应的 TypeAdapter 读取 JSON 串解析后得到一个 Java 对象;如果是对象类型,或者说所有系统预定义和用户自定义的 TypeAdapter 都无法解析这个类型,那就要使用最后一招,使用 ReflectiveTypeAdapter 以反射的方式遍历对象的属性,然后再对属性类型 Type 进行判断,这样就形成递归,直到遇见属性值是基本类型。
下面要开始结合源码看详细流程了,先上流程图:
主要分为三个阶段:
- 初始化 Gson,可以通过 Gson 的空参构造方法,也可以通过 GsonBuilder 的 create()。两种方式主要都是向 List<TypeAdapterFactory> factories 成员中添加各种数据类型对应的 TypeAdapterFactory。
- 读取 JSON 字符串
3.1 Gson 初始化
Gson 使用了装饰(门面)模式,它的内部很复杂,并不像我们使用时通过 new Gson() 创建个 Gson 对象,然后调用 toJson() 和 fromJson() 就完成了序列化和反序列化这么简单。
Gson 初始化主要有两种方式,一是调用 Gson 的空参构造方法,二是通过 GsonBuilder 设置参数,最后调用 create() 创建 Gson 对象。我们先关注空参构造方法:
public Gson() {
this(Excluder.DEFAULT, FieldNamingPolicy.IDENTITY,
Collections.<Type, InstanceCreator<?>>emptyMap(), DEFAULT_SERIALIZE_NULLS,
DEFAULT_COMPLEX_MAP_KEYS, DEFAULT_JSON_NON_EXECUTABLE, DEFAULT_ESCAPE_HTML,
DEFAULT_PRETTY_PRINT, DEFAULT_LENIENT, DEFAULT_SPECIALIZE_FLOAT_VALUES,
LongSerializationPolicy.DEFAULT, null, DateFormat.DEFAULT, DateFormat.DEFAULT,
Collections.<TypeAdapterFactory>emptyList(), Collections.<TypeAdapterFactory>emptyList(),
Collections.<TypeAdapterFactory>emptyList());
}
Gson(Excluder excluder, FieldNamingStrategy fieldNamingStrategy,
Map<Type, InstanceCreator<?>> instanceCreators, boolean serializeNulls,
boolean complexMapKeySerialization, boolean generateNonExecutableGson, boolean htmlSafe,
boolean prettyPrinting, boolean lenient, boolean serializeSpecialFloatingPointValues,
LongSerializationPolicy longSerializationPolicy, String datePattern, int dateStyle,
int timeStyle, List<TypeAdapterFactory> builderFactories,
List<TypeAdapterFactory> builderHierarchyFactories,
List<TypeAdapterFactory> factoriesToBeAdded) {
// 排除器
this.excluder = excluder;
// 字段命名策略
this.fieldNamingStrategy = fieldNamingStrategy;
// 反射创建对象时需要用到的构造器对象
this.instanceCreators = instanceCreators;
this.constructorConstructor = new ConstructorConstructor(instanceCreators);
this.serializeNulls = serializeNulls;
this.complexMapKeySerialization = complexMapKeySerialization;
this.generateNonExecutableJson = generateNonExecutableGson;
this.htmlSafe = htmlSafe;
this.prettyPrinting = prettyPrinting;
this.lenient = lenient;
this.serializeSpecialFloatingPointValues = serializeSpecialFloatingPointValues;
this.longSerializationPolicy = longSerializationPolicy;
this.datePattern = datePattern;
this.dateStyle = dateStyle;
this.timeStyle = timeStyle;
this.builderFactories = builderFactories;
this.builderHierarchyFactories = builderHierarchyFactories;
// TypeAdapterFactory 容器
List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>();
// built-in type adapters that cannot be overridden
factories.add(TypeAdapters.JSON_ELEMENT_FACTORY);
factories.add(ObjectTypeAdapter.FACTORY);
// the excluder must precede all adapters that handle user-defined types
factories.add(excluder);
// users' type adapters
factories.addAll(factoriesToBeAdded);
// type adapters for basic platform types
factories.add(TypeAdapters.STRING_FACTORY);
factories.add(TypeAdapters.INTEGER_FACTORY);
factories.add(TypeAdapters.BOOLEAN_FACTORY);
factories.add(TypeAdapters.BYTE_FACTORY);
factories.add(TypeAdapters.SHORT_FACTORY);
// 省略 N 多个 factories.add()
// 创建 @JsonAdapter 指定的自定义适配器对象的工厂
this.jsonAdapterFactory = new JsonAdapterAnnotationTypeAdapterFactory(constructorConstructor);
factories.add(jsonAdapterFactory);
factories.add(TypeAdapters.ENUM_FACTORY);
// 最后添加反射的 ReflectiveTypeAdapterFactory()
factories.add(new ReflectiveTypeAdapterFactory(
constructorConstructor, fieldNamingStrategy, excluder, jsonAdapterFactory));
this.factories = Collections.unmodifiableList(factories);
}
构造方法中初始化的主要内容:
- 排除器 Excluder 是一个 TypeAdapter,它用来处理不参与序列化的属性,比如 @Expose 注解中指定为 false 的部分,@Since 和 @Until 注解中不包含的字段版本,还有 static transient 修饰的字段不会序列化等等。
- FieldNamingStrategy 接口,是字段命名策略,就是把字段名称重新命名成 JSON 字段名。很像 @SerializedName 注解的功能。
- ConstructorConstructor 根据不同的数据类型返回一个构造器。在将 JSON 转换成 JavaBean 的时候需要创建其对象,如果我们没有自定义一个 TypeAdapter,那么 Gson 会使用默认的反射的方式来创建对象,此时需要用到构造器。
- List<TypeAdapter> factories 是所有 TypeAdapter 的列表。添加有顺序,最先添加进去的,优先级越高。排除器 -> 用户自定义 TypeAdapter -> 系统自带的 TypeAdapter -> 反射使用的 ReflectiveTypeAdapterFactory.Adapter。
再来看 GsonBuilder,它使用构造者模式初始化上述属性,其中各种 TypeAdapter 需通过 registerTypeAdapter() 添加:
public GsonBuilder registerTypeAdapter(Type type, Object typeAdapter) {
// typeAdapter 的类型是 Object,它必须实现下列四个接口之一
$Gson$Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?>
|| typeAdapter instanceof JsonDeserializer<?>
|| typeAdapter instanceof InstanceCreator<?>
|| typeAdapter instanceof TypeAdapter<?>);
if (typeAdapter instanceof InstanceCreator<?>) {
instanceCreators.put(type, (InstanceCreator) typeAdapter);
}
if (typeAdapter instanceof JsonSerializer<?> || typeAdapter instanceof JsonDeserializer<?>) {
TypeToken<?> typeToken = TypeToken.get(type);
factories.add(TreeTypeAdapter.newFactoryWithMatchRawType(typeToken, typeAdapter));
}
if (typeAdapter instanceof TypeAdapter<?>) {
factories.add(TypeAdapters.newFactory(TypeToken.get(type), (TypeAdapter)typeAdapter));
}
return this;
}
很明显,初始化阶段最重要的工作就是将所有的 TypeAdapter 添加到 List<TypeAdapterFactory> 类型的列表中供后续解析使用。
3.2 反序列化
反序列化的起点是 Gson 的 fromJson():
public <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
boolean isEmpty = true;
boolean oldLenient = reader.isLenient();
// 打开 reader 的标准化检验
reader.setLenient(true);
try {
// 1.内部调用 JsonReader 的 doPeek()
reader.peek();
isEmpty = false;
// TypeToken 本质上是 Class 的增强封装类
TypeToken<T> typeToken = (TypeToken<T>) TypeToken.get(typeOfT);
// 2.根据 TypeToken 获取可以处理其类型的 TypeAdapter
TypeAdapter<T> typeAdapter = getAdapter(typeToken);
// 3.创建 JavaBean 并返回
T object = typeAdapter.read(reader);
return object;
} catch (EOFException e) {
/*
* For compatibility with JSON 1.5 and earlier, we return null for empty
* documents instead of throwing.
*/
if (isEmpty) {
return null;
}
throw new JsonSyntaxException(e);
} catch (IllegalStateException e) {
throw new JsonSyntaxException(e);
} catch (IOException e) {
// TODO(inder): Figure out whether it is indeed right to rethrow this as JsonSyntaxException
throw new JsonSyntaxException(e);
} finally {
// 关闭 reader 的标准化检验
reader.setLenient(oldLenient);
}
}
主要分三步:
- JsonReader 调用 peek() 解析 JSON 字符
- 先获取目标类型 typeOfT 对应的 TypeToken,再获取能处理 TypeToken 的 TypeAdapter
- 执行 TypeAdapter 的 read() 反序列化得到一个 T 类型的对象
下面分别来看这三步的具体操作。
JsonReader 解析 JSON 字符
JsonReader 的 peek() 会在不消费掉下一个 Token 的情况下返回其类型:
public JsonToken peek() throws IOException {
int p = peeked;
if (p == PEEKED_NONE) {
// 判断栈顶字符类型
p = doPeek();
}
switch (p) {
case PEEKED_BEGIN_OBJECT:
return JsonToken.BEGIN_OBJECT;
case PEEKED_END_OBJECT:
return JsonToken.END_OBJECT;
case PEEKED_BEGIN_ARRAY:
return JsonToken.BEGIN_ARRAY;
case PEEKED_END_ARRAY:
return JsonToken.END_ARRAY;
// NAME、BOOLEAN、NULL、STRING、NUMBER 省略...
case PEEKED_EOF:
return JsonToken.END_DOCUMENT;
default:
throw new AssertionError();
}
}
关键要看 doPeek() 是如何解析 Token 的:
/**
* 1.stack 是 JsonReader 的成员变量,初始化时会给第一个元素赋值为 JsonScope.EMPTY_DOCUMENT,
* 表示还未开始读取对象或列表:stack[stackSize++] = JsonScope.EMPTY_DOCUMENT;
* 2.nextNonWhitespace() 会将 JSON 字符串转存为 char 类型数组,并以 int 值的形式返回
* 下一个要解析的 char 字符
* 3.peeked 是 JsonReader 用于状态控制的成员变量,它与 stack 协同控制 JsonReader 的逻辑行为
* 4.lenient 表示 JsonReader 是否接受不符合规范的 JSON,初始化为 false 表示不接受。在 checkLenient()
* 中如果 lenient 为 false 就会抛异常,提示用户通过 setLenient(true) 使 JsonReader 接受不合规范的 JSON
*/
int doPeek() throws IOException {
int peekStack = stack[stackSize - 1];
if (peekStack == JsonScope.EMPTY_ARRAY) {
stack[stackSize - 1] = JsonScope.NONEMPTY_ARRAY;
} else if (peekStack == JsonScope.NONEMPTY_ARRAY) {
// Look for a comma before the next element.
int c = nextNonWhitespace(true);
switch (c) {
case ']':
return peeked = PEEKED_END_ARRAY;
case ';':
// 检查标准协议选项,JSON 标准中的符号没有分号
checkLenient(); // fall-through
case ',':
break;
default:
throw syntaxError("Unterminated array");
}
} else if (peekStack == JsonScope.EMPTY_OBJECT || peekStack == JsonScope.NONEMPTY_OBJECT) {
stack[stackSize - 1] = JsonScope.DANGLING_NAME;
// Look for a comma before the next element.
if (peekStack == JsonScope.NONEMPTY_OBJECT) {
int c = nextNonWhitespace(true);
switch (c) {
case '}':
return peeked = PEEKED_END_OBJECT;
case ';':
checkLenient(); // fall-through
case ',':
break;
default:
throw syntaxError("Unterminated object");
}
}
int c = nextNonWhitespace(true);
switch (c) {
case '"':
return peeked = PEEKED_DOUBLE_QUOTED_NAME;
case '\'':
checkLenient();
return peeked = PEEKED_SINGLE_QUOTED_NAME;
case '}':
if (peekStack != JsonScope.NONEMPTY_OBJECT) {
return peeked = PEEKED_END_OBJECT;
} else {
throw syntaxError("Expected name");
}
default:
checkLenient();
pos--; // Don't consume the first character in an unquoted string.
if (isLiteral((char) c)) {
return peeked = PEEKED_UNQUOTED_NAME;
} else {
throw syntaxError("Expected name");
}
}
} else if (peekStack == JsonScope.DANGLING_NAME) {
stack[stackSize - 1] = JsonScope.NONEMPTY_OBJECT;
// Look for a colon before the value.
int c = nextNonWhitespace(true);
switch (c) {
case ':':
break;
case '=':
checkLenient();
// buffer 是储存 JSON 字符串的 char[],pos 是已经读取到字符的数量指针,
// limit 是 buffer 的可用部分的总长
if ((pos < limit || fillBuffer(1)) && buffer[pos] == '>') {
pos++;
}
break;
default:
throw syntaxError("Expected ':'");
}
} else if (peekStack == JsonScope.EMPTY_DOCUMENT) {
// 因为 stack[0] 被初始化为 JsonScope.EMPTY_DOCUMENT,所以首次调用该方法会进入本条件
if (lenient) {
consumeNonExecutePrefix();
}
stack[stackSize - 1] = JsonScope.NONEMPTY_DOCUMENT;
} else if (peekStack == JsonScope.NONEMPTY_DOCUMENT) {
int c = nextNonWhitespace(false);
if (c == -1) {
return peeked = PEEKED_EOF;
} else {
checkLenient();
pos--;
}
} else if (peekStack == JsonScope.CLOSED) {
throw new IllegalStateException("JsonReader is closed");
}
// 2.根据下一个 Token 的内容更新并返回 peeked
int c = nextNonWhitespace(true);
// 2.1 下一个 Token 是普通符号的情况
switch (c) {
case ']':
if (peekStack == JsonScope.EMPTY_ARRAY) {
return peeked = PEEKED_END_ARRAY;
}
// fall-through to handle ",]"
case ';':
case ',':
// In lenient mode, a 0-length literal in an array means 'null'.
if (peekStack == JsonScope.EMPTY_ARRAY || peekStack == JsonScope.NONEMPTY_ARRAY) {
checkLenient();
pos--;
return peeked = PEEKED_NULL;
} else {
throw syntaxError("Unexpected value");
}
case '\'':
checkLenient();
return peeked = PEEKED_SINGLE_QUOTED;
case '"':
return peeked = PEEKED_DOUBLE_QUOTED;
case '[':
return peeked = PEEKED_BEGIN_ARRAY;
case '{':
return peeked = PEEKED_BEGIN_OBJECT;
default:
pos--; // Don't consume the first character in a literal value.
}
// 2.2 下一个 Token 是关键字的情况,包括 true、false 和 null
int result = peekKeyword();
if (result != PEEKED_NONE) {
// result != PEEKED_NONE 说明下个字符确实是一个关键字
return result;
}
// 2.3 下一个 Token 是数字的情况
result = peekNumber();
if (result != PEEKED_NONE) {
return result;
}
// isLiteral() 用于检查符号是否合法,如 / \\ ; # = 这些符号会触发 checkLenient()
// 检测,在不接受非规范字符的情况下会抛出异常;而 {} [] : , 空格 \t \f \r \n 这些
// 符号会返回 false 表示不合法;其余符号会落入默认情况返回 true
if (!isLiteral(buffer[pos])) {
throw syntaxError("Expected value");
}
checkLenient();
return peeked = PEEKED_UNQUOTED;
}
获取 TypeAdapter
然后在 getAdapter() 中获取可以处理 TypeAdapter 的适配器:
// 缓存
private final Map<TypeToken<?>, TypeAdapter<?>> typeTokenCache = new ConcurrentHashMap<TypeToken<?>, TypeAdapter<?>>();
private static final TypeToken<?> NULL_KEY_SURROGATE = TypeToken.get(Object.class);
// 用 ThreadLocal 保存 Map<TypeToken<?>, FutureTypeAdapter<?>>
private final ThreadLocal<Map<TypeToken<?>, FutureTypeAdapter<?>>> calls
= new ThreadLocal<Map<TypeToken<?>, FutureTypeAdapter<?>>>();
public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
// 缓存中如果直接找到了 type 对应的 TypeAdapter 就直接返回
TypeAdapter<?> cached = typeTokenCache.get(type == null ? NULL_KEY_SURROGATE : type);
if (cached != null) {
return (TypeAdapter<T>) cached;
}
// 从 calls 这个缓存池中获取当前线程缓存
Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get();
// 清理 calls() 的标记位
boolean requiresThreadLocalCleanup = false;
// 如果当前线程的缓存还未创建,则创建并设置给 calls,同时置位 requiresThreadLocalCleanup
if (threadCalls == null) {
threadCalls = new HashMap<TypeToken<?>, FutureTypeAdapter<?>>();
calls.set(threadCalls);
requiresThreadLocalCleanup = true;
}
// 如果在当前线程的缓存中找到了 type 对应的 TypeAdapter,就直接返回
// the key and value type parameters always agree
FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type);
if (ongoingCall != null) {
return ongoingCall;
}
// threadCalls 缓存未命中,只能创建 TypeAdapter
try {
FutureTypeAdapter<T> call = new FutureTypeAdapter<T>();
threadCalls.put(type, call);
// 按先后顺序遍历 factories,如果找到能处理 type 的 TypeAdapterFactory 就返回
for (TypeAdapterFactory factory : factories) {
TypeAdapter<T> candidate = factory.create(this, type);
if (candidate != null) {
// 如果找到 candidate,就设置给 FutureTypeAdapter 的 delegate 去执行“读写” JSON 的操作。
// FutureTypeAdapter 是 TypeAdapter 的子类,让其内部的代理去真正的做(反)序列化。
call.setDelegate(candidate);
typeTokenCache.put(type, candidate);
return candidate;
}
}
// 如果没有 TypeAdapter 能处理 type 则抛出这个异常
throw new IllegalArgumentException("GSON (" + GsonBuildConfig.VERSION + ") cannot handle " + type);
} finally {
// 缓存清理
threadCalls.remove(type);
if (requiresThreadLocalCleanup) {
calls.remove();
}
}
}
获取 JavaBean 对象
拿到 TypeAdapter 对象后,调用其 read() 就可以反序列化得到一个 JavaBean 对象了。以 TypeAdapters 中预定义的 String 类型的 TypeAdapter 为例:
public static final TypeAdapter<String> STRING = new TypeAdapter<String>() {
@Override
public String read(JsonReader in) throws IOException {
JsonToken peek = in.peek();
if (peek == JsonToken.NULL) {
in.nextNull();
return null;
}
/* coerce booleans to strings for backwards compatibility */
if (peek == JsonToken.BOOLEAN) {
return Boolean.toString(in.nextBoolean());
}
return in.nextString();
}
@Override
public void write(JsonWriter out, String value) throws IOException {
out.value(value);
}
};
read() 的写法基本上都是先调用 JsonReader 的 peek() 取出一个 JsonToken 然后对其类型进行检查,排除 null 和其它不合理的类型后,再读取目标类型数据。更详细的用法,可以参考基础篇中【3.4 对字段空值的处理->自定义 TypeAdapter】一节的内容。
序列化的方法调用链与反序列化类似,Gson 的 toJson() 中会调用 TypeAdapter 的 write(),真正执行写操作的是 JsonWriter 的 value(),其在 string() 中会输出 JSON 字符串。具体代码就不贴了,有兴趣的自己去研究下。
4、反射解析原理
在 getAdapter() 获取 TypeAdapter 对象时,如果没有自定义的 TypeAdapter 可以处理目标类型,那么解析工作将落到 ReflectiveTypeAdapterFactory 内的 Adapter 上,它会使用反射的方式来解析这个类型。流程图如下:
4.1 初始化 Adapter
ReflectiveTypeAdapterFactory 的 create() 会创建其内部类 Adapter 的对象:
@Override public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {
Class<? super T> raw = type.getRawType();
if (!Object.class.isAssignableFrom(raw)) {
return null; // it's a primitive!
}
// type 类型的构造器对象,反射创建 type 对象时使用
ObjectConstructor<T> constructor = constructorConstructor.get(type);
return new Adapter<T>(constructor, getBoundFields(gson, type, raw));
}
Adapter 的构造方法会初始化两个成员变量:
public static final class Adapter<T> extends TypeAdapter<T> {
// T 类型的构造方法对象,反射创建 T 对象时用
private final ObjectConstructor<T> constructor;
// JSON 字符串中的属性集合
private final Map<String, BoundField> boundFields;
Adapter(ObjectConstructor<T> constructor, Map<String, BoundField> boundFields) {
this.constructor = constructor;
this.boundFields = boundFields;
}
}
这里我们有必要了解一下 ReflectiveTypeAdapterFactory 的另一个内部类 BoundField 以及 getBoundFields() 的内容:
static abstract class BoundField {
final String name; // 属性名称
final boolean serialized; // 是否序列化
final boolean deserialized; // 是否反序列化
protected BoundField(String name, boolean serialized, boolean deserialized) {
this.name = name;
this.serialized = serialized;
this.deserialized = deserialized;
}
abstract boolean writeField(Object value) throws IOException, IllegalAccessException;
abstract void write(JsonWriter writer, Object value) throws IOException, IllegalAccessException;
abstract void read(JsonReader reader, Object value) throws IOException, IllegalAccessException;
}
private Map<String, BoundField> getBoundFields(Gson context, TypeToken<?> type, Class<?> raw) {
Map<String, BoundField> result = new LinkedHashMap<String, BoundField>();
// 如果 raw 是一个接口,意味着它内部没有参与序列化/反序列化的属性(因为接口内声
// 明的属性默认是 public static final 的),因此直接返回一个空白的 result 即可。
if (raw.isInterface()) {
return result;
}
// 获取到参数类型
Type declaredType = type.getType();
// 递归遍历
while (raw != Object.class) {
Field[] fields = raw.getDeclaredFields();
for (Field field : fields) {
// 借助排除器 Excluder 判断该属性是否参与序列化与反序列化
boolean serialize = excludeField(field, true);
boolean deserialize = excludeField(field, false);
if (!serialize && !deserialize) {
continue;
}
accessor.makeAccessible(field);
// 获取属性类型
Type fieldType = $Gson$Types.resolve(type.getType(), raw, field.getGenericType());
// 获取属性名字,可能有多个,因为 @SerializedName 可以指定多个
List<String> fieldNames = getFieldNames(field);
BoundField previous = null;
// 只对第一个名字进行序列化,同时检查是否有多个属性使用了同一个名字
for (int i = 0, size = fieldNames.size(); i < size; ++i) {
String name = fieldNames.get(i);
if (i != 0) serialize = false; // only serialize the default name
// 创建 BoundField 对象
BoundField boundField = createBoundField(context, field, name,
TypeToken.get(fieldType), serialize, deserialize);
BoundField replaced = result.put(name, boundField);
if (previous == null) previous = replaced;
}
if (previous != null) {
throw new IllegalArgumentException(declaredType
+ " declares multiple JSON fields named " + previous.name);
}
}
// 更新递归条件,即下次循环要处理的数据类型
type = TypeToken.get($Gson$Types.resolve(type.getType(), raw, raw.getGenericSuperclass()));
raw = type.getRawType();
}
return result;
}
也就是说,创建 Adapter 的时候,就把 JSON 属性名封装到 BoundField 并存入 Map<String, BoundField> boundFields 集合中了,在这个过程中通过 createBoundField() 创建 BoundField 实例:
private ReflectiveTypeAdapterFactory.BoundField createBoundField(
final Gson context, final Field field, final String name,
final TypeToken<?> fieldType, boolean serialize, boolean deserialize) {
final boolean isPrimitive = Primitives.isPrimitive(fieldType.getRawType());
// special casing primitives here saves ~5% on Android...
JsonAdapter annotation = field.getAnnotation(JsonAdapter.class);
TypeAdapter<?> mapped = null;
if (annotation != null) {
// 如果使用 @JsonAdapter 指定了自定义适配器,则根据其类型(可能是 TypeAdapter、
// TypeAdapterFactory、JsonDeserializer)创建出对应的适配器对象
mapped = jsonAdapterFactory.getTypeAdapter(
constructorConstructor, context, fieldType, annotation);
}
final boolean jsonAdapterPresent = mapped != null;
// 如果在 @JsonAdapter 中没有找到适合的适配器,则从 Gson 的 factories 中找
if (mapped == null) mapped = context.getAdapter(fieldType);
final TypeAdapter<?> typeAdapter = mapped;
// 以匿名内部类的方式创建 BoundField 并返回
return new ReflectiveTypeAdapterFactory.BoundField(name, serialize, deserialize) {
@SuppressWarnings({"unchecked", "rawtypes"}) // the type adapter and field type always agree
@Override void write(JsonWriter writer, Object value)
throws IOException, IllegalAccessException {
Object fieldValue = field.get(value);
TypeAdapter t = jsonAdapterPresent ? typeAdapter
: new TypeAdapterRuntimeTypeWrapper(context, typeAdapter, fieldType.getType());
t.write(writer, fieldValue);
}
@Override void read(JsonReader reader, Object value)
throws IOException, IllegalAccessException {
// 通过 TypeAdapter 的 read() 反序列化出 Java 对象
Object fieldValue = typeAdapter.read(reader);
// 反射把对象设置给对应的字段
if (fieldValue != null || !isPrimitive) {
field.set(value, fieldValue);
}
}
@Override public boolean writeField(Object value) throws IOException, IllegalAccessException {
if (!serialized) return false;
Object fieldValue = field.get(value);
return fieldValue != value; // avoid recursion for example for Throwable.cause
}
};
}
注意 createBoundField() 获取 TypeAdapter 的顺序,先在 jsonAdapterFactory 找,如果没有,再调用 Gson 的 getAdapter() 去 factories 这个大集合中找,至少能找到使用反射的 ReflectiveTypeAdapterFactory.Adapter 作为结果。
4.2 反序列化
假如 fromJson() 内 getAdapter() 最终得到的是 ReflectiveTypeAdapterFactory.Adapter,调用其 read() 进行反序列化:
public static final class Adapter<T> extends TypeAdapter<T> {
private final ObjectConstructor<T> constructor;
private final Map<String, BoundField> boundFields;
@Override public T read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
// 用构造器反射创建出对象
T instance = constructor.construct();
try {
in.beginObject();
// 循环读取 JSON 的 name
while (in.hasNext()) {
// 读取 name 并获取对应的 BoundField
String name = in.nextName();
BoundField field = boundFields.get(name);
if (field == null || !field.deserialized) {
in.skipValue();
} else {
// 调用 BoundField 的 read() 来做反序列化
field.read(in, instance);
}
}
} catch (IllegalStateException e) {
throw new JsonSyntaxException(e);
} catch (IllegalAccessException e) {
throw new AssertionError(e);
}
in.endObject();
return instance;
}
}
- 遍历 JSON 的 name,获得 name 对应的 BoundField,再调用 BoundField 的 read();
- BoundField 的 read() 内会再调用处理这个 BoundField 的 TypeAdapter 的 read() 做反序列化。这里有两种情况,如果 TypeAdapter 是系统预定义或用户自定义的,通过 read() 可以反序列化出一个 Java 对象,那么就可以通过反射将这个对象设置给对应的字段;否则 TypeAdapter 就还只能是 ReflectiveTypeAdapterFactory.Adapter,调用它的 read() 就形成了递归,直到 BoundField 是一个非 ReflectiveTypeAdapterFactory.Adapter 可以处理的字段为止。
总结一下反射解析步骤:
- 反射的 ReflectiveTypeAdapterFactory 会在 Gson 的 factories 的末尾被添加,在 Gson 通过 getAdapter() 获取目标类型的适配器时,调用 create() 创建出 ReflectiveTypeAdapterFactory.Adapter 对象
- 如果目标类型没有被前面的自定义适配器处理,那么最后将用 ReflectiveTypeAdapterFactory.Adapter 的 read() 进行反序列化,遍历 JSON 内所有属性,并调用该属性对应的 BoundField 的 read()
- 抽象类 BoundField 的唯一子类是 createBoundField() 内作为返回值的匿名内部类,该类的 read() 再调用 TypeAdapter 的 read() 做反序列化。基本类型的 TypeAdapter 可以解析出一个 Java 对象,而非基本类型,或者预定义和自定义 TypeAdapter 都解析不了的类型,只能再用 ReflectiveTypeAdapterFactory.Adapter 做递归解析,直到所有字段都可以通过基本类型的 TypeAdapter 解析为止。