Gson的反射解析机制详解

转自:https://blog.csdn.net/chunqiuwei/article/details/49338053

 

在关于Gson的文章中我们知道Gson解析成Java对象的实现原理是: 
1)注册自定义的或者Gson自己定义的TypeAdapter 
2)将TypeAdapter封装成TypeAdapterFactory,并把此Factory添加到Gson的factories(List)中 
3)通过fromJson方法最终调用getAdapter,遍历factories,获取fromJson的第二个参数type与之对应的TypeAdapterFactory,调用该Factory的create方法来创建一个TypeAdapter 
4)调用TypeAdapter的read方法完成json到Java Object的转换。 
在我们使用Gson的时候对下面两行代码都不陌生:

Gson gson = new Gson();
Object obj = gson.fromJson(String,Object.class);


这两行代码中你看不到上面所说的任何一个步骤,那么Gson到底是怎么工作的呢?其实简单的追踪一下Gson(),其调用的是Gson的有参构造器,而在这个有参构造器里面就让Gson的factories变量添加了大量的自定义的TypeAdapterFactory,这些TypeAdapterFactory和与之对应的TypeAdapter基本上都在TypeAdapters类里面,当然也有其余的几个单独的TypeAdapter(详见博主写的前几篇关于Gson的博客)!

在正式进入博客主题之前提出一些小问题:在没有自定义自己的TypeAdapter的时候,Gson到底是怎么工作的呢?具体来说调用的是哪个TypeAdapterFactory?而这个TypeAdapterFactory又是create哪个TypeAdapter来完成json的read操作呢?

在回答上面的问题的时候,先说一个事实: 
对于每一个Java的基本类型或者集合类型等,Gson都提供了与之相对应的TypeAdapter类型,比如String 类型就有下面的一个TypeAdper:

//与之对应的TypeAdapterFactory
public static final TypeAdapterFactory CHARACTER_FACTORY = newFactory(char.class, Character.class, CHARACTER);
//StringTypeAdapter
public static final TypeAdapter<String> STRING = new TypeAdapter<String>() {
        @Override
        public String toString() {
            return "STRING TypeAdapter";
        }
        @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();
        }

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


基于上面的事实在追踪Gson提供的方法getAdapter方法就可以发现,Gson用反射机制解析Json的流程如下: 
前提:通过调用Gson的getAdpter来过滤掉一些不用的TypeAdapterFactory,将能用的到的TypeAdapterFactory放入缓存中,详见getAdapter的一个段代码:


      FutureTypeAdapter<T> call = new FutureTypeAdapter<T>();
      for (TypeAdapterFactory factory : factories) {
         //根据type来从gson的factro获取typeAdapter
        TypeAdapter<T> candidate = factory.create(this, type);
        //在解析过程中真正需要的TypeAdapter放入typeTokenCache
        //这个map对象中进行缓存
        if (candidate != null) {
          call.setDelegate(candidate);
          typeTokenCache.put(type, candidate);
          return candidate;
        }

  }


1)从factories中取ReflectiveTypeAdapterFactory对象 
2)调用ReflectiveTypeAdapterFactory的create方法,返回一个Adapter对象

 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);
    //创建一个Adapter对象
    return new Adapter<T>(constructor, getBoundFields(gson, type, raw));
  }


3)在通过Adpater的read方法循环读取json:循环解析json串中的每一对name/value,并为你的javaBean里的某个变量并赋值

//boundFields是个map集合,通过getBoundFields方法来初始化
//关于这个集合详见步骤四
public T read(JsonReader in) throws IOException {
    //此处有省略代码
      //创建对象的实例:这段至关重要
      T instance = constructor.construct();
        //直接读取一个JsonObject
        in.beginObject();
        while (in.hasNext()) {//遍历当前JsonObject的值
          //获取name
          String name = in.nextName();
         //获取这个name 绑定的变量名,也就是你JavaBean里定义的变量名
         //并返回BoundField操作
          BoundField field = boundFields.get(name);
          //读取当前name对应的值,并通过反射赋值给field
          //具体read是怎么实现的,见步骤5
          field.read(in, instance);//给当前field赋值

        }
      //此处有省略代码
      in.endObject();
      //此处有省略代码
    }


4)对于步骤三,具体的实现为:对每一个name/value对,根据你JavaBean里定义的对应变量的类型(type),通过回调(重新)调用Gson对象类的getAdpter方法获取对应类型的TypeAdapter对象(具体实现见步骤5),并通过read读取这个值!然后继续步骤三的while循环读取json中的以一个name/value,详细代码如下:

 /**
   初始化Map,key:name为json中某一name/value对的name
    value:当前name中对应的在JavaBean中变量的名,封装为BoundField
   **/
 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) {
     //获取你的Java类定义的变量
      Field[] fields = raw.getDeclaredFields();
      for (Field field : fields) {//遍歷變量的名字
        //省略部分代码
        field.setAccessible(true);
        Type fieldType = $Gson$Types.resolve(type.getType(), raw, field.getGenericType());
        //整整构建BoundField的地方,见步骤5
        BoundField boundField = createBoundField(context, field, getFieldName(field),
            TypeToken.get(fieldType), serialize, deserialize);
        BoundField previous = result.put(boundField.name, boundField);

      }
      type = TypeToken.get($Gson$Types.resolve(type.getType(), raw, raw.getGenericSuperclass()));
      raw = type.getRawType();
    }
    return result;
  }


5)以上四个步骤基本上就说明了json反射中的全部流程,在步骤3的while循环中,调用了BoundField的read方法,进行读取;其实BoundFied是一个抽象类,提供了read和write方法,其具体创建的方法是createBoundField方法:

    //参数name为json中某一name/value对的name的值
    private ReflectiveTypeAdapterFactory.BoundField createBoundField( final Gson context, final Field field, final String name,final TypeToken<?> fieldType, boolean serialize, boolean deserialize) {

//返回构建的BoundField对象
return new ReflectiveTypeAdapterFactory.BoundField(name, serialize, deserialize) {
      //此处最为关键,获取当前name对应的fiedType类型的TypeAdpater
      //获取对应变量类型的TypeAdpter,这个是关键中的关键
      //其中这些TypeAdapter是由Gson自己定义的
      final TypeAdapter<?> typeAdapter = context.getAdapter(fieldType);
      @SuppressWarnings({"unchecked", "rawtypes"}) // the type adapter and field type always agree
       //本篇只讲read,所以此处省略了write方法
      @Override void read(JsonReader reader, Object value)
          throws IOException, IllegalAccessException {
          //实际上的read仍然是typeAdapter对象的read来处理
        Object fieldValue = typeAdapter.read(reader);
        if (fieldValue != null || !isPrimitive) {
          field.set(value, fieldValue);
        }
      }
    };
  }


注意观察上面的代码:有这么一个核心的代码:

//获取当前json串的一个name/value的name对应JavaBean里面的变量类型type,或者这个type对应的TypeAdpater类
 final TypeAdapter<?> typeAdapter = context.getAdapter(fieldType);//获取对应的基本类型的

到此位置基本上说完了Gson反射的整体流程,附上流程图一个: 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值