轻触开源(三)-Gson项目源码解析_贰

转载请注明出处:https://my.oschina.net/u/874727/blog/750473java

Q:1025250620数据结构

非墨上一篇文文章说到:Gson经过传入的TypeToken类型,遍历Gson变量中的factorys工厂,来生成一个TypeAdapter的转换器。本章将细化这个生成过程。咱们依旧沿用上一次所定义的Json对象和Java数据模型,经过一个典型的例子来学习一下:在Gson项目中,是如何作到数据适配和转换的。app

// code 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;
		}
	}
...
//code main
String strJson = "{name:'david',age:19,room:{roomName:'small',number:1}}";
User u = gson.fromJson(strJson, User.class);

对于上面的例子,在Gson中,Gson将会用专门的适配器RefrectiveTypeAdapter来转换这种类型的数据。固然,这种适配器是顶层的适配器,对于里面的name,age这些属性,将会有不一样的适配器来生成。整个适配器的解析结构相似于装饰器。而用于构建RefrectiveTypeAdapter的工厂就是RefrectiveTypeAdapterFactory。Factory对TypeToken进行拦截,拦截的方式就是看是否能生成相应的Adapter对象。为了说明这点,咱们回到Gson的getAdapter的方法:ide

//code Gson
 for (TypeAdapterFactory factory : factories) {
    	...
        TypeAdapter<T> candidate = factory.create(this, type);
        ...
}

能够看出,Json是经过factory的create方法来判断,工厂是否知足构建的条件。同时,咱们还能够获得另一个结论:若是一个Json串能够被多个的factory.create方法拦截的话,那么他们是有优先顺序的。好比说对于String对象,它自己具备对象的属性,所以它能够被RefrectiveTypeAdapterFactory工厂所拦截。可是,因为TypeAdapters.STRING_FACTORY的拦截器位于RefrectiveTypeAdapterFactory的前面,因此String对象并不会选择RefrectiveTypeAdapterFactory,而选择TypeAdapters中的STRING_FACTORY拦截器。咱们先来看一下RefrectiveTypeAdapterFactory的create方法是如何拦截的:函数

//code ReflectiveTypeAdapterFactory.java
public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {
    Class<? super T> raw = type.getRawType();

    if (!Object.class.isAssignableFrom(raw)) {//code #1
      return null; // it's a primitive!
    }

    ObjectConstructor<T> constructor = constructorConstructor.get(type);
    //code #2
    return new Adapter<T>(constructor, getBoundFields(gson, type, raw));
  }

在code#1中,Factory作了拦截判断,而知足RefrectiveTypeAdapterFactory的构造条件是:工具

!Object.class.isAssignableFrom(raw)。对于isAssignableFrom方法的解释,咱们看一下文档:学习

/** object is either the same as, or is a superclass or
* superinterface of, the class or interface represented by the specified*/

根据文档的解释,咱们能够知道上面的判断语句是在判断raw是不是直接或者间接继承于Object或者自己就为一个Object(接口类型也返回true)。这主要是为了拦截一些基本类型,好比int和long。对于String对象的话也"能够"被RefrectiveTypeAdapterFactory拦截。可是就像非墨说的,这种拦截是有优先级的,谁的拦截靠前,谁就优先被选择。咱们来看下在Gson中所定义的factory拦截顺序:ui

// code Gson.init()
{
...
factories.add(TypeAdapters.STRING_FACTORY);
...
factories.add(new ReflectiveTypeAdapterFactory(
        constructorConstructor, fieldNamingPolicy, excluder));
...
}

能够看出,对于String类型来讲,因为TypeAdapters.STRING_FACOTRY的工厂拦截器更加靠前,所以对于特殊的基本类型String来讲,仍是会选择位于TypeAdapters中的基本类型工厂来处理。this

咱们继续回到RefrectiveTypeAdapterFactory这个类的create代码。在#code1 拦截完成以后,Factory构建了一个对象的构造器。上一篇(<轻触开源(二)-Gson项目源码解析_上>.net

https://my.oschina.net/u/874727/blog/749405)

咱们说到,Gson为了方便操纵一些东西,而使用本身的数据结构定义类型中的一些定义。而这个ObjectConsturctor就是为了方便对象构建而定义的构造器。

//code ObjectConstructor.java
 public <T> ObjectConstructor<T> get(TypeToken<T> typeToken) {
    final Type type = typeToken.getType();
    final Class<? super T> rawType = typeToken.getRawType();

    // first try an instance creator

    @SuppressWarnings("unchecked") // types must agree
    final InstanceCreator<T> typeCreator = 
(InstanceCreator<T>) instanceCreators.get(type);//#code1
    if (typeCreator != null) {//#code2
      return new ObjectConstructor<T>() {
        public T construct() {
          return typeCreator.createInstance(type);
        }
      };
    }

    // Next try raw type match for instance creators
    @SuppressWarnings("unchecked") // types must agree
    final InstanceCreator<T> rawTypeCreator =
        (InstanceCreator<T>) instanceCreators.get(rawType);
    if (rawTypeCreator != null) {//#code2
      return new ObjectConstructor<T>() {
        public T construct() {
          return rawTypeCreator.createInstance(type);
        }
      };
    }

    ObjectConstructor<T> defaultConstructor = 
           newDefaultConstructor(rawType);//#code3
    if (defaultConstructor != null) {
      return defaultConstructor;
    }

    ObjectConstructor<T> defaultImplementation = 
        newDefaultImplementationConstructor(type, rawType);//#code4
    if (defaultImplementation != null) {
      return defaultImplementation;
    }

    // finally try unsafe
    return newUnsafeAllocator(type, rawType);//#code5
  }

在#code1 中,Gson默认也用了缓冲区instanceCreators拦截。可是因为instanceCreators默认状况下为空集,因此咱们直接跳过。可是非墨但愿你们记录一下这个代码段,缘由是咱们在经过GsonBuilder构造Gson对象的时候,还会提到它。#code3里面,它会调用咱们默认声明的构造器。而#code4里会让Gson帮你选定一些类型和构造器。为何要让Gson帮你选定类型和构造器呢?这是由于你不少状况下你并不关心你的具体类型是什么,而这种状况经常用于传入接口类型:

String strJsonArr = "[{name:'david',age:19,room:{roomName:'small',number:1}},"
				+ " {name:'xdf',age:18,room:{roomName:'big',number:2}}]";
		List<User> list = gson.fromJson(strJsonArr, new TypeToken<List<User>>(){}.getType());

这个场景中,咱们并无传入具体类型,而是传入一个集合类接口List<User>。咱们并不关心Gson返回的具体类型是什么,只但愿返回的是一个集合类。为了解决这个问题,Gson会默认帮咱们选定一个具体类型。这就是#code4的具体功能。咱们回到刚才#code3的代码,Gson会优先调用类型的默认构造方法,而调用的方式是经过newDefaultConstructor方法。

private <T> ObjectConstructor<T> newDefaultConstructor(Class<? super T> rawType) {
    try {
      final Constructor<? super T> constructor = 
         rawType.getDeclaredConstructor();//获取无参数构造器
      if (!constructor.isAccessible()) {
        constructor.setAccessible(true);
      }
      return new ObjectConstructor<T>() {
        @SuppressWarnings("unchecked") // T is the same raw type as is requested
        public T construct() {
          try {
            Object[] args = null;
            return (T) constructor.newInstance(args);
          } catch (e) {
               ...
          } 
        }
      };
    } catch (NoSuchMethodException e) {
      return null;
    }
  }

实际上,newDefaultConstructor方法就是获取一下Type的无参数构造器。然而,若是咱们要用咱们本身的构造方法呢?还记得非墨上面让各位看官记录一下的instanceCreators么?是的,咱们就须要用到它,可是这部分,非墨将在后面说GsonBuilder的时候来描述它。

代码描述到这里,咱们已经得到了Type的构造器,也就是ReflectiveTypeAdapterFactory的代码咱们已经进行到了#code2的位置。

上面咱们将整个流程简单梳理了一遍,可是问题并无彻底解决。咱们知道对于User数据结构的构成,实际上分红好几个部分:

为了构建User对象你须要构建name属性,age属性和对象room属性。罗马并非一天建成的,对象也不是一次生成的。而这个构建的流程和属性里Adapter的选定,都在RefrectiveTypeAdapterFactory的create的最后一行代码中。

//code ReflectiveTypeAdapterFactory.java 
public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {
    ...
    return new Adapter<T>(constructor, getBoundFields(gson, type, raw));//#code1
}
//---
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);//#code1
        boolean deserialize = excludeField(field, false);//code2
        if (!serialize && !deserialize) {
          continue;
        }
        field.setAccessible(true);
        Type fieldType = $Gson$Types.resolve(type.getType(), raw, field.getGenericType());
        BoundField boundField = createBoundField(context, field, getFieldName(field),
            TypeToken.get(fieldType), serialize, deserialize);
        BoundField previous = result.put(boundField.name, boundField);
        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;
  }

RefrectiveTypeAdapterFactory.Adapter的生成,会调用getBoundsField方法,这个方法的目的就是为了分解对象中的属性参数,并以属性名和属性结构映射的方式返回。在Gson中,它会获取该对象的全部属性,并记录在本身的数据结构中。这样的好处在于,你可使用继承的方式来定义你本身的对象。Gson内部的Field数据结构是BoundField类。BoundField类是一个抽象类,分别有如下属性:

this.name = name;//属性名
this.serialized = serialized;//须要序列化
this.deserialized = deserialized;//可反序列化

而这些属性均可以经过注解的方式往对象类中配置,应用于不一样的应用场景。咱们看到上面的代码#code1,Gson获取传入类的所有Field,而后经过excludeField方法来解析后两个属性。

public boolean excludeField(Field f, boolean serialize) {
    return excludeField(f, serialize, excluder);
  }

  static boolean excludeField(Field f, boolean serialize, Excluder excluder) {
    return !excluder.excludeClass(f.getType(), serialize) && !excluder.excludeField(f, serialize);
  }

第二个参数serialize用于当前是序列化仍是反序列化,而后采用不一样的程序逻辑。这部分代码就跟它所定义的方法名字同样,为了排除掉一些没必要要的属性定义。对于那些不须要序列化和反序列化的属性,Gson是不作的备案。

Type fieldType = $Gson$Types
    .resolve(type.getType(), raw, field.getGenericType());// #code1
BoundField boundField = createBoundField(context, field, getFieldName(field),
            TypeToken.get(fieldType), serialize, deserialize);// #code2
BoundField previous = result.put(boundField.name, boundField);

识别完该属性是否须要序列化以后,对于要备案的属性,就要生成对应的BoundField对象。Gson经过工具类$Gson$Types来解析子域的类型,记录为fieldType。看官是否会感受很奇怪,既然你已经获得了field,直接获取类型不就行了么?为何要画蛇添足解析类型呢?回答这个问题咱们必需要回到<轻触开源>系列的第一章:轻触开源(一)-Java泛型Type类型的应用和实践

https://my.oschina.net/u/874727/blog/747427

Field的类型若是是泛型的话,因为它并不属于声明泛型的接口,所以,当Field的类型是一个泛型参数的时候,它的类型将依赖于外部类型。为了说明这点,咱们把咱们以前的Java模型稍微转换一下:

public static class ClassRoom{
		public String roomName;
		public long number;
		public String toString() {
			return "["+roomName+":"+number+"]";
		}
	}
	
	public static class User<T>{
		private T room;
		public String name;
		public int age;
		
		@Override
		public String toString() {
			// TODO Auto-generated method stub
			return name+"->"+age+":"+room;
		}
	}
     User<ClassRoom> usr = new User<ClassRoom>();

咱们能够看到,对于新的对象模型,room的类型的传入依赖于User类的泛型参数T。针对这个例子,咱们刚才调用#code1中的参数分别对应的值就是:

Type fieldType = $Gson$Types
    .resolve(
type.getType(), // class Test2$User<Test2$ClassRoom>
raw, // Test2$User
field.getGenericType() //T
);// #code1

因为子域field中的类型为泛型参数T,所以它的具体类型依赖于类型自己的泛型参数。咱们根据这个例子来看下Gson是如何解析的。

public static Type resolve(
     Type context, //域的上下文,即直接包含在外侧的类型
     Class<?> contextRawType, 
     Type toResolve//域定义的类型
) {
    // this implementation is made a little more complicated in an attempt to avoid object-creation
    while (true) {
      if (toResolve instanceof TypeVariable) {//case1
        TypeVariable<?> typeVariable = (TypeVariable<?>) toResolve;
        toResolve = resolveTypeVariable(context, contextRawType, typeVariable);
        if (toResolve == typeVariable) {
          return toResolve;
        }

      } else if(...){
        ...
      } else {
        return toResolve;
      }
    }
  }

根据咱们第一章对泛型的解释,咱们能够清楚的知道,对于T类型的变量,所传入的Field的Type类型是TypeVariable类型。所以程序将经过case1条件语句,这就进入到resolveTypeVariable方法。

static Type resolveTypeVariable(
Type context, 
Class<?> contextRawType,
TypeVariable<?> unknown//#code1 
) {
    Class<?> declaredByRaw = declaringClassOf(unknown);//#code2
    /**//#code declaringClassOf
        private static Class<?> declaringClassOf(TypeVariable<?> typeVariable) {
        GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
          return genericDeclaration instanceof Class
          ? (Class<?>) genericDeclaration
          : null;
        }
    */

    // we can't reduce this further
    if (declaredByRaw == null) {
      return unknown;
    }

    Type declaredBy = 
   getGenericSupertype(context, contextRawType, declaredByRaw);//#code3
    if (declaredBy instanceof ParameterizedType) {//#code4
      int index = indexOf(declaredByRaw.getTypeParameters(), unknown);
      return ((ParameterizedType) declaredBy).getActualTypeArguments()[index];
    }

    return unknown;
  }

代码的参数名再次帮咱们验证了咱们的猜想,unknown正好说明这个函数就是在field类型未知的状况下所进行的操做。#code2中函数declaringClassOf的代码已经在注释中展开。这个函数的目的是为了返回一个GenericDeclaration的接口。而这个接口,相信各位看官并不陌生。若是须要回顾的话请查看个人第一篇文章:<轻触开源(一)-Java泛型Type类型的应用和实践>

https://my.oschina.net/u/874727/blog/747427

第一章咱们说到,GenericDeclaration是用于标识那些能够用于泛型声明的接口。所以咱们不难推断出,对于上述咱们的例子中,变量room的T类型的声明就是源自于User类。所以,declaringClassOf所返回的就是User的Type。接着#code3和#code4的代码就很浅显了。#code3用于得到User的全部泛型参数,而#code4找到这些泛型参数中所对应的T的实际类型。

好的,咱们大概对Gson解析子域类型有了基本的流程,咱们再次回到BoundField的构造代码:

Type fieldType = $Gson$Types
    .resolve(type.getType(), raw, field.getGenericType());// #code1
BoundField boundField = createBoundField(context, field, getFieldName(field),
            TypeToken.get(fieldType), serialize, deserialize);// #code2
BoundField previous = result.put(boundField.name, boundField);

在#code2中,RefrectiveTypeAdapterFactory经过方法$Gson$Types
    .resolve获得的Field的具体fieldType,来生成Gson本身的内部对象BoundField。这里咱们能够注意一下getFieldName方法,咱们知道Gson中的序列化名字是能够配置的。而它的实现就隐藏在这个方法中。

static String getFieldName(FieldNamingStrategy fieldNamingPolicy, Field f) {
    SerializedName serializedName = f.getAnnotation(SerializedName.class);
    return serializedName == null ? fieldNamingPolicy.translateName(f) : serializedName.value();
  }

getFieldName方法中,咱们能够看到,在Gson获取Field的name的时候,会优先查看在你的Field上是否包含有@SerializedName注解,若是有的话将使用注解里的Value值。若是没有的话,将使用Gson本身的命名策略,里面的策略有不少种,能够在GsonBuilder中配置,本章就不展开讲,有兴趣的看官能够本身研究。那么咱们再回到上面的#code2中,接下去程序将经过createBoundField方法来构造一个BoundField:

return new ReflectiveTypeAdapterFactory.BoundField(name, serialize, deserialize) {
      final TypeAdapter<?> typeAdapter = 
      getFieldAdapter(context, field, fieldType);//#code1
      /**code getFieldAdapter()
      private TypeAdapter<?> getFieldAdapter(Gson gson, Field field, TypeToken<?> fieldType) {
         JsonAdapter annotation = field.getAnnotation(JsonAdapter.class);//#code1.1
         if (annotation != null) {
         TypeAdapter<?> adapter = getTypeAdapter(constructorConstructor, gson, fieldType, annotation);
          if (adapter != null) return adapter;
         }
         return gson.getAdapter(fieldType);
      }
      */
      @Override void write(JsonWriter writer, Object value){
        TypeAdapter t =
          new TypeAdapterRuntimeTypeWrapper(context, this.typeAdapter, fieldType.getType());
        t.write(writer, fieldValue);
      }
    
      @Override void read(JsonReader reader, Object value)
          throws IOException, IllegalAccessException {
        Object fieldValue = typeAdapter.read(reader);
        if (fieldValue != null || !isPrimitive) {
          field.set(value, fieldValue);
        }
      }
 
      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方法里,会构造一个匿名的BoundField对象。其中,会经过调用(#code1)getFieldAdapter方法来生成BoundField的TypeAdapter。而getFieldAdapter的代码,非墨已经直接粘到注释中。在getFieldAdapter中,Gson会先去查看你的Field中是否标记有JsonAdapter的注解。这个注解的值必须是Class对象,而Class对象的限定条件必须是TypeAdapter类型或者是TypeAdapterFactory类型。若是Field中并无标记JsonAdapter注解,那么Gson会调用Gson类中的getAdapter方法返回默认的Adapter。或许有些看官对这些概念看的云里雾里。没关系,非墨用一段代码来带各位实践一下。咱们依旧对以前所定义的Java对象User进行改造,而且定义咱们本身的一个TypeAdapter:

public static class User<T>{
		@JsonAdapter(MyAdapter.class)
		private T room;
		public String name;
		public int age;
		
		@Override
		public String toString() {
			// TODO Auto-generated method stub
			return name+"->"+age+":"+room;
		}
}
//class MyAdapter
public class MyAdapter extends TypeAdapter<String> {

	@Override
	public void write(JsonWriter out, String value) throws IOException {}

	@Override
	public String read(JsonReader in) throws IOException {
		StringBuilder builder = new StringBuilder();
		in.beginObject();
		builder.append(in.nextName()).append("-");
		builder.append(in.nextString()).append("-");
		builder.append(in.nextName()).append("-");
		builder.append(in.nextString());
		in.endObject();
		return builder.toString();
	}

}

咱们经过上述的JsonAdapter注解来指定room类型所须要的适配器MyAdapter。这个适配器咱们返回一个String类型。也就是说,最后被注入到User的room变量中的类型是String类型。咱们打印下最后的结果获得:

Gson gson = new Gson();
		String strJsonArr = "{name:'david',age:19,room:{roomName:'small',number:1}}";
		User<ClassRoom> usr = gson.fromJson(strJsonArr, new TypeToken<User<ClassRoom>>(){}.getType());
		System.out.println(usr);
//输出"david->19:roomName-small-number-1"

各位看官是否还对上面的执行代码感到疑惑?首先我经过泛型已经指定了room变量为ClassRoom类型,可是你返回的是String类型,为何可以注入的你的对象中,而且你的程序并无出错?

这个问题咱们又得回到本系列的第一章,非墨一直在强调,对于泛型的处理,java虚拟机只是将它控制在编译期。在执行期的时候,无非就是在特定的状况下加入了一下classcast的指令。若是咱们将usr.room的class打印一下,这个时候Java编译器会在此次调用以后进行一个classCast的操做,这时候,程序才会中断抛出异常。

System.out.println("user = "+usr.room.getClass());
//输出 Exception in thread "main" java.lang.ClassCastException

(待续)

相关文章
相关标签/搜索