ReflectiveTypeAdapterFactory完成Field属性之后,将生成TypeAdapter返回。Gson通过Adapter来生成指定类型的对象。生成对象的过程,被ReflectiveTypeAdapterFactory.Adapter类记录在自己的read方法中:
@Override public T read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
T instance = constructor.construct();
try {
in.beginObject();
while (in.hasNext()) {
String name = in.nextName();
BoundField field = boundFields.get(name);
if (field == null || !field.deserialized) {
in.skipValue();
} else {
field.read(in, instance);
}
}
} catch (IllegalStateException e) {
throw new JsonSyntaxException(e);
} catch (IllegalAccessException e) {
throw new AssertionError(e);
}
in.endObject();
return instance;
}
Gson采用注入的方式往已生成的对象中注入属性。在注入之前,会先调用ObjectConstructor来生成所需要的对象。这部分,非墨已经在之前的文章中表述过了。由于ReflectiveTypeAdapterFactory.Adapter针对的是Gson对象的适配,因此在适配之前,会先调用JsonReader.beginObject来声明处理入口。
//CODE JsonReader.java
public void beginObject() throws IOException {
int p = peeked;
if (p == PEEKED_NONE) {
p = doPeek();
}
if (p == PEEKED_BEGIN_OBJECT) {
push(JsonScope.EMPTY_OBJECT);
peeked = PEEKED_NONE;
} else {
throw new IllegalStateException("Expected BEGIN_OBJECT but was " + peek()
+ " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath());
}
}
private void push(int newTop) {
if (stackSize == stack.length) {
int[] newStack = new int[stackSize * 2];
int[] newPathIndices = new int[stackSize * 2];
String[] newPathNames = new String[stackSize * 2];
System.arraycopy(stack, 0, newStack, 0, stackSize);
System.arraycopy(pathIndices, 0, newPathIndices, 0, stackSize);
System.arraycopy(pathNames, 0, newPathNames, 0, stackSize);
stack = newStack;
pathIndices = newPathIndices;
pathNames = newPathNames;
}
stack[stackSize++] = newTop;
}
JsonReader调用beginObject方法,会调用push方法用于记录一下当前操作的词汇元素。这里将记录一个JsonScope.EMPTY_OBJECT的变量。我们用以下Json串用于测试:
String strJson = "{\"name\":david,age:19,room:{roomName:small,number:1}}";
这个Json串将被记录在JsonReader的Buffer中。Gson在调用fromJson的时候,会调用一下JsonReader的peek操作,而peek操作,会调用内部的doPeek操作,doPeek操作会改变JsonReader中peeked变量的值和buffer偏移pos。peeked变量用于记录下一个字符的属性,pos变量用于记录buffer缓存的偏移量。
此时,在Gson.fromJson中调用完reader的peek方法之后,JsonReader中pos索引的位置将指向' " '符号。
我们回到ReflectiveTypeAdapterFactory的Adapter的read方法中去看:
@Override public T read(JsonReader in) throws IOException {
...
try {
in.beginObject();
while (in.hasNext()) {
String name = in.nextName();
BoundField field = boundFields.get(name);
if (field == null || !field.deserialized) {
in.skipValue();
} else {
field.read(in, instance);
}
}
} catch (IllegalStateException e) {
throw new JsonSyntaxException(e);
} catch (IllegalAccessException e) {
throw new AssertionError(e);
}
in.endObject();
return instance;
}
Gson在调用完beginObject之后调用了JsonReader的hasNext方法,这个方法顾名思义,就是用来查看输入源中是否还有待处理的字符。之后,如果此项为真,那么将调用JsonReader.nextName方法来获取Json对象的属性名字。
public String nextName() throws IOException {
int p = peeked;
if (p == PEEKED_NONE) {
p = doPeek();
}
String result;
if (p == PEEKED_UNQUOTED_NAME) {
result = nextUnquotedValue();
} else if (p == PEEKED_SINGLE_QUOTED_NAME) {
result = nextQuotedValue('\'');
} else if (p == PEEKED_DOUBLE_QUOTED_NAME) {
result = nextQuotedValue('"');
} else {
throw new IllegalStateException("Expected a name but was " + peek()
+ " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath());
}
peeked = PEEKED_NONE;
pathNames[stackSize - 1] = result;
return result;
}
nextName方法会先调用一个peek,查看下Buffer流的第一个字符是什么属性,并且只给三个属性给出了不同的操作,分别是:
PEEKED_UNQUOTED_NAME :对应 name:value
PEEKED_SINGLE_QUOTED_NAME : 对应 'name':value
PEEKED_DOUBLE_QUOTED_NAME: 对应 "name":value
如果你希望Gson严格按照规范执行,也就是说你对Gson语法的宽容度为false(调用JsonReader.setLenient(false))。那么你所传入的Json串,只要涉及到String类型的数据,都必须采用PEEKED_DOUBLE_QUOTED_NAME方式记录。
在调用完不同类型的getName方法之后,取得第一个name值:"name"。之后将通过这个name来取得在对象field映射表boundFields中的BoundField值:
BoundField field = boundFields.get(name);
if (field == null || !field.deserialized) {
in.skipValue();
} else {
field.read(in, instance);
}
如果你的Field已经标注为不被反序列化,或者Json串中的name在你的对象中根本没被标记,JsonReader将通过skipValue来过滤掉这些无用的信息。但是如果映射表中存在有这样的Field,Adapter将调用BoundField的read方法来讲读取出来的值,注入到之前生成的instance对象中去。BoundField的read方法在ReflectiveTypeAdapterFactory中,以匿名类的方式来实现,
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...
return new ReflectiveTypeAdapterFactory.BoundField(name, serialize, deserialize) {
final TypeAdapter<?> typeAdapter = getFieldAdapter(context, field, fieldType);
....
@Override void read(JsonReader reader, Object value)
throws IOException, IllegalAccessException {
Object fieldValue = typeAdapter.read(reader);
if (fieldValue != null || !isPrimitive) {
field.set(value, fieldValue);
}
}
....
};
}
private TypeAdapter<?> getFieldAdapter(Gson gson, Field field, TypeToken<?> fieldType) {
JsonAdapter annotation = field.getAnnotation(JsonAdapter.class);
if (annotation != null) {
TypeAdapter<?> adapter = getTypeAdapter(constructorConstructor, gson, fieldType, annotation);
if (adapter != null) return adapter;
}
return gson.getAdapter(fieldType);
}
BoundField会通过自己的TypeAdapter来read一个Value,然后通过调用set方法,往生成对象中注入。而内部的TypeAdapter的生成是通过getFieldAdapter方法来生成的,具体的内容,请参照非墨的上篇文章:
<轻触开源(三)-Gson项目源码解析_贰 https://my.oschina.net/u/874727/blog/750473>
来源:oschina
链接:https://my.oschina.net/u/874727/blog/751417