我们使用Gson的时候基本是需要先定义一个数据模型,然后通过一个String流转化为我们OO的对象。那么对于一个框架来说,如何去获得用户想要的数据类型呢?并且我们又要如何通过这种既定的类型来构造出我们需要的对象?或许你的第一反应就是传递一个Clazz进去,然后通过反射的方法来获得我们的实际对象。跟着这个想法我们来实验一下:
public <T>T createObject(Class<T> clazz) { try { return (T)clazz.newInstance(); } catch (Exception e) { return null; } }
我们知道对于普通类型的对象我们可以通过Gson提供的fromJson(String,Clazz)来直接生成我们OO层的对象:
public <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException { Object object = fromJson(json, (Type) classOfT); return Primitives.wrap(classOfT).cast(object); }
public class TypeToken<T> { final Class<? super T> rawType; final Type type; final int hashCode; @SuppressWarnings("unchecked") protected TypeToken() { this.type = getSuperclassTypeParameter(getClass()); this.rawType = (Class<? super T>) $Gson$Types.getRawType(type); this.hashCode = type.hashCode(); } }
/** * Returns the type from super class's type parameter in {@link $Gson$Types#canonicalize * canonical form}. */ static Type getSuperclassTypeParameter(Class<?> subclass) { Type superclass = subclass.getGenericSuperclass(); if (superclass instanceof Class) { throw new RuntimeException("Missing type parameter."); } ParameterizedType parameterized = (ParameterizedType) superclass; return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]); }由于外部不得不采用匿名类的方式来生成TypeToken<?>,因此,你需要获得的泛型类型包含在你的superclass信息中。假如你的匿名类不包含任何的泛式类型,就会抛出一个"Miss type paramter"异常。我们不妨简单定义一个泛式类型来看一下调用getGenericSuperClazz后得到的东西:
public class MySub extends MyGson<List<String>> {}我们执行一个getGenericSuperclass()操作,得到的是一个ParameterizedType 类型的Type。而这个Type包含有你几乎关心的所有类型元数据。包括它的拥有者,它的类名,他的泛型参数。
我们之前提到过任何以$打头的都是Gson提供的静态工具类。canonicalize 方法的目的是规范我们在泛型内的参数,并且转化成Gson自己既定的数据结构。那什么叫做规范呢?我们还是使用MySub类作为例子,我们得到的superclass的type是MyGson<List<String>>,由于它只有一个泛型参数,因此parameterized.getActualTypeArguments()[0]方法调用之后的结果就是List<String>这个Type。或许你很纳闷为什么我们需要一个Type类呢?实际上我们知道类是对象是类的个体,个体的集合可以抽象成为类,那么类型如果作为个体,描述类型的类就是Type。或许你还是一头雾水,不要紧,这并不影响我们对Gson源码的分析,我们跟进到$Gson$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; } }关于Type类的继承树的(http://docs.oracle.com/javase/6/docs/api/java/lang/reflect/Type.html)。
从上面的代码,我们可以比较清楚的看出,Gson对每一Type都转化为自己的数据结构,原因很简单,因为你无法很直接的获取到jdk内部的接口实现。我们打开一个Type实现类看看:
public ParameterizedTypeImpl(Type ownerType, Type rawType, Type... typeArguments) { // require an owner type if the raw type needs it if (rawType instanceof Class<?>) { Class<?> rawTypeAsClass = (Class<?>) rawType; checkArgument(ownerType != null || rawTypeAsClass.getEnclosingClass() == null); checkArgument(ownerType == null || rawTypeAsClass.getEnclosingClass() != null); } this.ownerType = ownerType == null ? null : canonicalize(ownerType); this.rawType = canonicalize(rawType); this.typeArguments = typeArguments.clone(); for (int t = 0; t < this.typeArguments.length; t++) { checkNotNull(this.typeArguments[t]); checkNotPrimitive(this.typeArguments[t]); this.typeArguments[t] = canonicalize(this.typeArguments[t]); } }
实际上,Gson相当于clone了一便JDK内部的数据类型,差别就在于,这个数据结构可以由Gson框架自己控制。此外,我们可以很清楚的看出Gson内部,采用递归的方式来创建内部数据类型。举个例子来说明:
String gsonValue = "[{name:'非子墨',age:23},{name:'非墨',age:23}]"; TypeToken typeToken = new TypeToken<User[]>(){};我们通过Gson的TypeToken获得一个User数组类型,那么按照我们之前的分析,它会调用到$Gson$Type的canonicalize方法,由于User[]是一种数据类型,因此它在canonicalize 方法中走的case就是:
if (type instanceof GenericArrayType) { GenericArrayType g = (GenericArrayType) type; returnType = new GenericArrayTypeImpl(g.getGenericComponentType()); }我们接着往下走,跟到GenericArrayTypeImpl的内部看看
public GenericArrayTypeImpl(Type componentType) { this.componentType = canonicalize(componentType); }我们看到在数组类型,采用递归的方式记录了数据类型中成员的类型数据。之所以要调用canonicalize就是要将它转化为Gson自己的数据类型。通过这种方式,Gson构建出自己的一个类型树,基本就完成了类型的采取。
原文地址:http://blog.csdn.net/hello__zero/article/details/44201033