上篇文章<轻触开源-Java泛型Type类型的应用和实践(一)>java
http://www.javashuo.com/article/p-pzkygieh-dn.htmljson
非墨写到JAVA的泛型机制,被用到不少的开源项目。在众多的开源项目中,Gson是很具备表明性的一个。Gson是Google公司编写的一套用于Json数据转化为Java对象的一套通用工具库。之因此说它是通用工具库,是由于它的实现代码所有基于最基础的Java运行时环境,而不依赖于任何系统平台,也就是说你不只能够在J2EE项目中应用它,你同样能够很容易的在Android,J2ME等等平台中直接应用它。缓存
Gson跟不少的开源操纵了Java内部数据类型的项目相同,为了方便记录类型数据,Gson会将Java原有的一套数据类型,转化为本身的内部数据类型。好比,在上一章咱们提到的在Java泛型中记录类型的Class和Type类型,就被Gson转化为TypeToken。WildcardType转化为Gson本身的WildcardTypeImpl,GenericArrayType转为了Gson的内部类型GenericArrayTypeImpl。而这些类型的定义都被记录在com.google.gson.internal包中。咱们从这个包名也看的很明白,就是Gson系统将一些转换的细节屏蔽到Gson项目的内部,而只暴露给用户一些简单的接口。安全
但不论Gson如何转变既定的Java类型,实际上都只是在Java的既定类型外加一层壳,能够说是一个类适配器,好比咱们来看一下WildcardTypeImpl的代码:多线程
private static final class WildcardTypeImpl implements WildcardType, Serializable { private final Type upperBound; private final Type lowerBound; public WildcardTypeImpl(Type[] upperBounds, Type[] lowerBounds) { checkArgument(lowerBounds.length <= 1); checkArgument(upperBounds.length == 1); if (lowerBounds.length == 1) { checkNotNull(lowerBounds[0]); checkNotPrimitive(lowerBounds[0]); checkArgument(upperBounds[0] == Object.class); this.lowerBound = canonicalize(lowerBounds[0]); this.upperBound = Object.class; } else { checkNotNull(upperBounds[0]); checkNotPrimitive(upperBounds[0]); this.lowerBound = null; this.upperBound = canonicalize(upperBounds[0]); } } public Type[] getUpperBounds() { return new Type[] { upperBound }; } public Type[] getLowerBounds() { return lowerBound != null ? new Type[] { lowerBound } : EMPTY_TYPE_ARRAY; } @Override public boolean equals(Object other) { return other instanceof WildcardType && $Gson$Types.equals(this, (WildcardType) other); } @Override public int hashCode() { // this equals Arrays.hashCode(getLowerBounds()) ^ Arrays.hashCode(getUpperBounds()); return (lowerBound != null ? 31 + lowerBound.hashCode() : 1) ^ (31 + upperBound.hashCode()); } @Override public String toString() { if (lowerBound != null) { return "? super " + typeToString(lowerBound); } else if (upperBound == Object.class) { return "?"; } else { return "? extends " + typeToString(upperBound); } } private static final long serialVersionUID = 0; }
WildcardType对象中最重要的upper和lower参数,实际上都是由外部对象传入,在Gson的WildcardTypeImpl内部,不过是作了一层适配器。好的,咱们先预热到这里,咱们进入咱们今天的主题Gson的源码。ide
在咱们深刻讲Gson源码以前,咱们先用一下Gson这个库,领略一下它的魅力。所以咱们先构建两个基础的Java模型:函数
public static class ClassRoom{ public String roomName; public int number; public String toString() { return "["+roomName+":"+number+"]"; } } public static class User{ public String name; public int age; private ClassRoom room; @Override public String toString() { // TODO Auto-generated method stub return name+"->"+age+":"+room; } }
模型是用于记录用户信息以及班级信息。为了映射这个对象数据,咱们编写一个简单Json字符:工具
String strJson = "{name:'david',age:19,room:{roomName:'small',number:1}}"; User u = gson.fromJson(strJson, User.class);
最后咱们能够将生成的u对象打印一下获得:测试
david->19:[small:1]
各位看官是否被惊艳到?是的,使用Gson就是能够这么容易的转换Json对象。虽然咱们还没开始阅读Gson的源代码,可是咱们能够从传入的参数简单看出,在Gson的实现中,必定是大量用到了Java的反射注入技术。咱们看下Gson的分包:ui
gson的分包很简单,从名字上看,每一个包分类的目的也都很明确。在Gson中,从普通的Json对象到Gson对象的转换,是经过internal包及其子包bind中的适配器TypeAdapter完成的。而这种完成的类型数据,是依赖于reflect中记录的Type信息来完成的。适配器所须要的输入源或者输出源,是来自于stream包的数据流。当你的对象模型有一些特殊的输出需求或者输入需求,能够经过annotation包中的注解来操纵你的元数据。为了说明这一切,咱们回头看一下咱们的测试代码,在代码中,咱们是直接调用了Gson.fromJson方法。当咱们跟踪fromJson这个方法到最后,咱们会发现Gson.fromJson方法最终会调用到方法块:
//file:"com/google/gson/Gson.java" @SuppressWarnings("unchecked") public <T> T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException { JsonReader jsonReader = new JsonReader(json);// step1 T object = (T) fromJson(jsonReader, typeOfT); assertFullConsumption(object, jsonReader); return object; } @SuppressWarnings("unchecked") public <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException { boolean isEmpty = true; boolean oldLenient = reader.isLenient(); reader.setLenient(true); try { reader.peek();//step2 isEmpty = false; TypeToken<T> typeToken = (TypeToken<T>) TypeToken.get(typeOfT);//step3 TypeAdapter<T> typeAdapter = getAdapter(typeToken);//step4 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.setLenient(oldLenient); } }
就像咱们上面说的同样,在代码#step1 中,Gson会将真实的字符IO流Reader装饰成为在stream包下的JsonReader流。在代码#step3位置,Gson会经过Java既定的类型找到Gson所转换的type类型(reflect包下的TypeToken对象)。而后经过这个类型调用代码#step4的语句,获取一个类型转换的适配器TypeAdapter。适配器获取到Reader输入源以后,就能够将Json数据转化成为对应的对象。
TypeToken采用一种懒加载的机制来生成TypeToken。这种机制在程序代码中很是常见。
/** * Gets type literal for the given {@code Type} instance. */ public static TypeToken<?> get(Type type) { return new TypeToken<Object>(type); } @SuppressWarnings("unchecked") protected TypeToken() { this.type = getSuperclassTypeParameter(getClass()); this.rawType = (Class<? super T>) $Gson$Types.getRawType(type); this.hashCode = type.hashCode(); } /** * Unsafe. Constructs a type literal manually. */ @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(); }
咱们能够看到,TypeToken.get方法,其实是生成了一个TypeToken对象。而对于TypeToken对象的生成,在TypeToken类中有两种构造方式。第一种无参数的构造方式的做用域设置为protected,意味着你必需要经过继承的方式才能使用它,而且所须要转化的类型须要经过继承里的泛型参数指定。而第二种构造方法须要传入一个Type对象。而这个Type对象就是咱们上一篇文章中的Type对象(四种直接子接口和一个实现类)。而Java中的Type类型到Gson中的对象映射,就由$Gson$Type的canonicalize方法完成:
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; } }
Gson在将数据源传入给适配器Adapter作转换操做的以前,会有一个peek操做。peek跟咱们日常用到的流的peek没有什么差别,都是不弹出流数据的状况下查看缓冲区数据。这个peek操做的目的是为了肯定以何种输入源类型来处理Json对象。好比,当你输入的JSON串为:
{name:david}
的时候,因为输入员peek出来的是一个"{"字符。在JsonReader对象中,会以"PEEKED_BEGIN_OBJECT" 变量标记peek状态量。而若是你的Json数据是:
[{name:david},{name:Lily}]
的话,因为JsonReader.peek出来的数据是"["字符,所以peek状态量会标记为"PEEKED_BEGIN_ARRAY"。
public JsonToken peek() throws IOException { int p = peeked; if (p == PEEKED_NONE) { p = doPeek(); } .... default: throw new AssertionError(); } }
因为JsonReader咱们是刚刚生成,所以peeked状态量的默认值,也就是PEEKED_NONE.这样,程序就跳转到函数doPeek()中。
private int doPeek() throws IOException { int peekStack = stack[stackSize - 1];//状态栈 ... }
JsonReader使用栈式的解析,stack存放JsonScope常量所枚举的对象。这个栈中主要存放解析过程当中所操纵的对象类型。因为目前Json解析还没有开始,目前栈中存放的是默认值"EMPTY_DOCUMENT"
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; }
以后根据读入的第一个字符"{"或者"["返回具体的类型,对于"{"字符,将返回一个"PEEKED_BEGIN_OBJECT"类型。
private void doPeek() { ... int c = nextNonWhitespace(true);//取得第一个非空白字符 switch (c) { ... case '[': return peeked = PEEKED_BEGIN_ARRAY; case '{': return peeked = PEEKED_BEGIN_OBJECT; } ... }
但从代码功能上来看,实际上讲Reader.peek代码放在Adapter.read代码前的任何位置都不影响逻辑。咱们再继续以前的代码段:
//com.google.gson.Gson fromJson() 1.reader.peek(); 2.isEmpty = false; 3.TypeToken<T> typeToken = (TypeToken<T>) TypeToken.get(typeOfT); 4.TypeAdapter<T> typeAdapter = getAdapter(typeToken); 5.T object = typeAdapter.read(reader); 6.return object;
第1行代码,咱们经过peek来记录一下Json的最外层对象类型
第3行代码,咱们用过传入的类型来生成了一个Gson的类型对象TypeToken
第4行代码,咱们经过第三行代码生成的TypeToken对象生成一个数据转换的适配器
第5行代码,咱们经过适配器,将输入源中的Json数据转换为Java中的数据对象
上面咱们已经说到了第三行代码,TypeToken.get方法调用后,new了一个TypeToken对象。
// code1 @SuppressWarnings("unchecked") public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) { TypeAdapter<?> cached = typeTokenCache.get(type);//#1 缓存TypeAdapter if (cached != null) { return (TypeAdapter<T>) cached; } Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get();//#2 线程安全 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>();//#3无用的类装饰 threadCalls.put(type, call); for (TypeAdapterFactory factory : factories) { TypeAdapter<T> candidate = factory.create(this, type);//#4查找对应的工厂 if (candidate != null) { call.setDelegate(candidate); typeTokenCache.put(type, candidate); return candidate; } } throw new IllegalArgumentException("GSON cannot handle " + type); } finally { threadCalls.remove(type); if (requiresThreadLocalCleanup) { calls.remove(); } } }
Gson在获取TypeAdapter的时候,会先从线程的Cache中去取,代码#1很好的诠释了这一点。而为了保证在多线程状态下的状态稳定性,Gson给每一个线程都设定了一个Map类型的Cache。#2以后的代码就是在完成这么一项工做。在#3代码里Gson引入了一个新的类FutureTypeAdapter。这个类实际上没有什么实际上的意义,因此能够忽略它。在代码#4的时候,Gson经过遍历本身的factories列表来生成一个TypeAdapter对象。实际上在这一步,Gson在作一个Factory选择,咱们来看一个Factory的例子:
// code CollectionTypeAdapterFactory.java public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { Type type = typeToken.getType(); Class<? super T> rawType = typeToken.getRawType(); if (!Collection.class.isAssignableFrom(rawType)) { #1 集合类判断 return null; } ... TypeAdapter<T> result = new Adapter(gson, elementType, elementTypeAdapter, constructor); return result; }
这是一个集合类TypeAdapter生成的例子。代码#1就是经过判断传入的对象类型是不是集合类型来进行选择。
(待续)