作者 | 负了时光不负卿
地址 | http://www.jianshu.com/p/f723a5ac6e37
声明 | 本文是 负了时光不负卿 原创,已获授权发布,未经原作者允许请勿转载
闯入背景
公司项目中使用 Gson 框架对服务器传过来的 Json 数据进行解析,而服务器后台数据很大程度上是通过运营后台人员配置。由于各种原因运营可能将某一字段类型配置错误,比如集合类型配置成字符串类型。虽然业务层会进行异常的捕获,但是仅因为一个字段的错误,导致整个 Json 数据失效,因小失大,甚至可能会造成重大损失,比如直播间礼物墙,因为一个礼物的某一个字段的错误,导致整个礼物墙展示为空,在线上环境这个算是重大事故了。于是,一个对基本类型容错的 Gson 改造库的需求油然而生,对于错误的数据以默认值填充。
干货地址:类型容错的 Gson
https://github.com/1004145468/IKGson
Gson官方库地址
Github地址
https://github.com/1004145468/IKGson
前提说明
a. 当前分析的 Gson 版本号为 2.8.1。
b. Gson 的处理过程主要分为两个流向,一个是序列化,将 javabean 对象转化为 json 字符串;另一个是反序列化,将 json 字符串映射成javabean 对象。
c. 这两个流向处理前都有一个共同的操作,从传入的 java 实例对象或者字节码对象中获取 TypeAdapter,对于序列化就通过 Jsonwriter 进行写,对于反序列化就通过 JsonReader 进行读,所以此篇只分析 Gson 读的过程,写处理操作流程一样。
Gson 关键列的梳理
Gson 开发者直接使用的类,只对输入和输出负责。
TypeToken 封装“操作类”(Gson.fromJson(json,People.class、Gson.toJson(new People)) 两处的 People 都是操作类)的类型。
TypeAdapter 直接操作序列化与反序列化的过程,所以该抽象类中存在 read() 和 write 方法。
TypeAdapterFactory 用于生产 TypeAdapter 的工厂类。
GsonReader 和 GsonWriter是 Gson 处理内容的包装流,核心的操作有:
peek() 流中下一个需要处理的内容
nextName() 读取 json 的 key
nextString() 读取一个 String 类型的 value
nextInt() 读取一个 String 类型的 value
nextBoolean() 读取一个 Boolean 类型的 value
...
源码分析
从 Gson.from(json, People.class) 突入
fromJson(json,Peolple.class)的调用链 public <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException { Object object = fromJson(json, (Type) classOfT); return Primitives.wrap(classOfT).cast(object); } public <T> T fromJson(String json, Type typeOfT) throws JsonSyntaxException { if (json == null) { return null; } StringReader reader = new StringReader(json); T target = (T) fromJson(reader, typeOfT); return target; } public <T> T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException { JsonReader jsonReader = newJsonReader(json); T object = (T) fromJson(jsonReader, typeOfT); assertFullConsumption(object, jsonReader); return object; } public <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException { boolean isEmpty = true; boolean oldLenient = reader.isLenient(); reader.setLenient(true); try { reader.peek(); isEmpty = false; TypeToken<T> typeToken = (TypeToken<T>) TypeToken.get(typeOfT); TypeAdapter<T> typeAdapter = getAdapter(typeToken); T object = typeAdapter.read(reader); return object; } ... }
上面是从 fromJson(String json, Class classOfT) 切入,亦或者是从fromJson(JsonElement json, Class classOfT) 也好,最终都是由 fromJson(JsonReader reader, Type typeOfT) 处理。
整个 Json 的解析过程分三步过程:
TypeToken 对象的获取
根据 TypeToken 获取 TypeAdapter 对象
由 TypeAdapter 对象解析 json 字符串
根据以上的三步,我们逐一突破
我们先从简单的入手,请记住我们的例子:
gson.fromJson("hello gson",String.class)
TypeToken 的获取
public static TypeToken<?> get(Type type) { return new TypeToken<Object>(type); }
没什么好瞅的~ 看 new 吧!
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(); }
采用契约式对传入的 type 判空处理,然后获取 type 的(type、rawType 和 hashcode),分别看看 type 和 rawtype 的获取流程
type 的获取(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; }
进入条件的筛选,第一个if还是好理解,后面的是什么鬼? 不用着急,待我给施主梳理,之前 Gson.from(json, People.class)的调用链中有一个 fromJson(Reader json, Type typeOfT)
,用户使用时的切入点如果是它就可能是筛选情况的其他条件,此返回的 type 相对于对传入的java类型进行的类型的重新包装。
rawType 的获取(type 的简单粗暴说明)
public static Class<?> getRawType(Type type) { if (type instanceof Class<?>) { // type is a normal class. return (Class<?>) type; } else if (type instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) type; // I'm not exactly sure why getRawType() returns Type instead of Class. // Neal isn't either but suspects some pathological case related // to nested classes exists. Type rawType = parameterizedType.getRawType(); checkArgument(rawType instanceof Class); return (Class<?>) rawType; } else if (type instanceof GenericArrayType) { Type componentType = ((GenericArrayType)type).getGenericComponentType(); return Array.newInstance(getRawType(componentType), 0).getClass(); } else if (type instanceof TypeVariable) { // we could use the variable's bounds, but that won't work if there are multiple. // having a raw type that's more general than necessary is okay return Object.class; } else if (type instanceof WildcardType) { return getRawType(((WildcardType) type).getUpperBounds()[0]); } else { String className = type == null ? "null" : type.getClass().getName(); throw new IllegalArgumentException("Expected a Class, ParameterizedType, or " + "GenericArrayType, but <" + type + "> is of type " + className); } }
两处对比的看,其实 type 和 rawtype 很相似,type 通过类来包装说明,而 rawtype 脱去华丽的衣服。type 为GenericArrayType 的,把衣服一脱,赤身裸体的一看,擦,原来是个 array 数组,这就是 rawtype。
TypeAdapter的获取。
public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) { TypeAdapter<?> cached = typeTokenCache.get(type == null ? NULL_KEY_SURROGATE : type); if (cached != null) { return (TypeAdapter<T>) cached; } Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get(); boolean requiresThreadLocalCleanup = false; if (threadCalls == null) { threadCalls = new HashMap<TypeToken<?>, FutureTypeAdapter<?>>(); calls.set(threadCalls); requiresThreadLocalCleanup = true; } // the key and value type parameters always agree FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type); if (ongoingCall != null) { return ongoingCall; } try { FutureTypeAdapter<T> call = new FutureTypeAdapter<T>(); threadCalls.put(type, call); for (TypeAdapterFactory factory : factories) { TypeAdapter<T> candidate = factory.create(this, type); if (candidate != null) { call.setDelegate(candidate); typeTokenCache.put(type, candidate); return candidate; } } throw new IllegalArgumentException("GSON cannot handle " + type); }
如果缓存中没有该 Type 对应 TypeAdapter,就创建 TypeAdapter。前面提过 TypeAdapter是由TypeAdapterFactory创建的,所以有代码:
for (TypeAdapterFactory factory : factories) { TypeAdapter<T> candidate = factory.create(this, type); if (candidate != null) { call.setDelegate(candidate); typeTokenCache.put(type, candidate); return candidate; } }
遍历所有的 TypeAdapterFactory,如果该工厂能创建该 Type 的 TypeAdapter 就返回该TypeAdapter对象。
那么重点来了,factories 这么多的 TypeAdapterFactory 是怎么来了的?
在我们 new Gson 的时候,就往 factories 中塞入了不同类型的TypeAdapterFactory,包括 StringTypeAdapterFactory等等,代码如下:
public Gson(xxx) { ... factories.add(TypeAdapters.STRING_FACTORY); 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); ... }
在遍历 factories 过程中通过 create(this,type)方法来生成TypeAdapter。
我们就以第一个 STRING_FACTORY 为例先进行说明。
public static final TypeAdapterFactory STRING_FACTORY = newFactory(String.class, STRING);
接着往下看
public static <TT> TypeAdapterFactory newFactory( final Class<TT> type, final TypeAdapter<TT> typeAdapter) { return new TypeAdapterFactory() { @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { return typeToken.getRawType() == type ? (TypeAdapter<T>) typeAdapter : null; } @Override public String toString() { return "Factory[type=" + type.getName() + ",adapter=" + typeAdapter + "]"; } }; }
STRINGFACTORY = newFactory(String.class, STRING) 的时候,STRING 就是处理 String 类型的 TypeAdapter,STRINGFACTORY中的create方法就是判断需要处理的类型是不是 String 类型的,如果是就返回 STRING,否则返回 null,即该类型不用 STRING 来处理。
总的来说,在创建 Gson 的实例对象时,创建 TypeAdapterFactory 的集合。每种 TypeAdapterFactory 实例包含能处理的 Type 类型和 Type类型的 TypeAdapter,不能处理的 Type 类型返回的 TypeAdapter 为null,所以在遍历 factories 过程中有:
for (TypeAdapterFactory factory : factories) { TypeAdapter<T> candidate = factory.create(this, type); if (candidate != null) { ... return candidate; } }
由TypeAdapter对象解析 json字符串
我们回到最初的代码:
TypeToken<T> typeToken = (TypeToken<T>)TypeToken.get(typeOfT);TypeAdapter<T> typeAdapter = getAdapter(typeToken);T object = typeAdapter.read(reader);
STRING就是处理String类型的TypeAdapter,然后我们看它的read()方法。
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(); } ... };
到这里位置,我们就将 gson.fromJson("hello gson",String.class) 的 String类型“hello gson”返回。
刚刚是只是牛刀小试,我们的主材料来了,看看有多丰盛...
Gson.from("{"name": "zhangsan","age": 15,"grade": [95,98]}", Student.class)
我们重新走刚刚的流程,看看怎么处理的
Step one : 获取TypeToken
这一步没有什么与众不同
Step Two: TypeAdapter的获取。
factories中包含了很多基本类型的TypeAdapterFactory,同时也包含用户自定义的类型Factory,看源码: // type adapters for composite and user-defined types factories.add(new CollectionTypeAdapterFactory(constructorConstructor)); factories.add(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization)); this.jsonAdapterFactory = new JsonAdapterAnnotationTypeAdapterFactory(constructorConstructor); factories.add(jsonAdapterFactory); factories.add(TypeAdapters.ENUM_FACTORY); factories.add(new ReflectiveTypeAdapterFactory(constructorConstructor, fieldNamingStrategy, excluder, jsonAdapterFactory));
此处我们能匹配上的是 ReflectiveTypeAdapterFactory,然后我们看它的 create()方法,关键的地方到了!!!
@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! } ObjectConstructor<T> constructor = constructorConstructor.get(type); return new Adapter<T>(constructor, getBoundFields(gson, type, raw)); }
a. constructorConstructor 获取 Student 类的构造器
b. getBoundFields() 通过反射获取 Student 每一个字段的的TypeAdapter,并且包装到 Map 中,后面会讲解getBoundFields()的方法。
Step Three 通过 TypeAdapter的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; }
到了这一步就似乎海阔天空了,通过传入的构造器创建 Student 类的实例,在 JsonReader 进行处理,in.beginObject() 相当于跳过“{”,in.endObject()相当于跳过“}”,其中通过in.hasNext()判断是否处理完成。
在 in.nextName() 读取 json 字符串中的 key 值,然后在boundFields 根据key获取对应的 BoundField ,最后调用BoundField.read(in,instance) 去处理细节,即每个字段的映射,我们看一下内部的细节:
new ReflectiveTypeAdapterFactory.BoundField(name, serialize, deserialize) { ... @Override void read(JsonReader reader, Object value) throws IOException, IllegalAccessException { Object fieldValue = typeAdapter.read(reader); if (fieldValue != null || !isPrimitive) { field.set(value, fieldValue); } } ... };
当 Filed 都处理完成后,instance 实例的每一个需要处理的字段都赋值成功,最终将这个对象 return出去。
细节说明:
a. getBoundFields()
private Map<String, BoundField> getBoundFields(Gson context, TypeToken<?> type, Class<?> raw) { Map<String, BoundField> result = new LinkedHashMap<String, BoundField>(); if (raw.isInterface()) { return result; } Type declaredType = type.getType(); while (raw != Object.class) { Field[] fields = raw.getDeclaredFields(); for (Field field : fields) { boolean serialize = excludeField(field, true); boolean deserialize = excludeField(field, false); if (!serialize && !deserialize) { continue; } field.setAccessible(true); Type fieldType = $Gson$Types.resolve(type.getType(), raw, field.getGenericType()); 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 = 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; }
遍历Student类的每一个字段,遍历过程中做了两件事情:
a. 该字段能否被序列化和反序列化,如果都不行就没有必要处理该字段,主要通过注解和排除器(Excluder)进行判断。
b. 对字段进行 BoundField 的包装。
b. JsonReader.doPeek()
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 ';': 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(); if ((pos < limit || fillBuffer(1)) && buffer[pos] == '>') { pos++; } break; default: throw syntaxError("Expected ':'"); } } else if (peekStack == 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"); } int c = nextNonWhitespace(true); 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. } int result = peekKeyword(); if (result != PEEKED_NONE) { return result; } result = peekNumber(); if (result != PEEKED_NONE) { return result; } if (!isLiteral(buffer[pos])) { throw syntaxError("Expected value"); } checkLenient(); return peeked = PEEKED_UNQUOTED; }
该操作逻辑处理较强,主要工作分为 3 点:
json 的格式校验,格式不合法抛出异常
根据当前的操作,决定下一步的操作方式
流中下一部分的内容类型
点赞转发都是对我最大的支持!,节日快乐哈
本文暂时没有评论,来添加一个吧(●'◡'●)