Gson的反射解析机制详解(1)
来源:互联网 发布:竞品数据分析 编辑:程序博客网 时间:2024/06/03 17:24
在 几篇关于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:
//与之对应的TypeAdapterFactorypublic static final TypeAdapterFactory CHARACTER_FACTORY = newFactory(char.class, Character.class, CHARACTER);//StringTypeAdapterpublic 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 { //此处有省略代码 //直接读取一个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反射的整体流程,附上流程图一个:
下面用一个例子来结束本博客:
{ "isbn": "978-0321336781", "title": "Java Puzzlers: Traps, Pitfalls, and Corner Cases", "soldout":true, "authors": [ { "id": 1, "name": "Joshua Bloch" }, { "id": 2, "name": "Neal Gafter" } ]}
对应的JavaBean如下:
public class Book2{ //作者类 private Author[] authors; private String isbn; private String title; private boolean soldout;//是否卖完 }class Author { private int id; private String name;}
当解析这个json串的时候,因为对应的JavaBen变量的类型有String,int ,Boolean,Array类型,会调用TypeAdapters里面的INTEGER、STRING、BOOLEAN 这些TypeAdapter,以及ArrayTypeAdapter。当然由于需要映射成JavaObject,所以需要用到反射功能的ReflectiveTypeAdapterFactory返回的newAdapter(),在本例的解析中两次用到了ReflectiveTypeAdapterFactory,第一次是解析Book的时候,第二次是解析json数组中的jsonObject映射成Author对象的时候。
到此就结束了Gson反射机制流程的说明,如果错误甚至不当之处欢迎批评指正。
- Gson的反射解析机制详解(1)
- Gson的反射解析机制详解(2)
- 利用Java的反射机制,写了一个简单的仿Gson的解析器
- 数据的解析 Gson的使用详解
- Java 的反射机制详解
- java的反射机制详解
- 详解reflectJava的反射机制
- 详解reflectJava的反射机制
- JAVA的反射机制详解
- Java的反射机制详解
- Gson解析(详解)
- Gson解析json详解
- Gson解析使用详解
- 简单的案例解析Java反射机制
- Java反射机制的运用-Json解析
- JAVA 反射机制解析
- 反射机制简单解析
- java反射机制解析
- iOS开发UI篇—iPad和iPhone开发的比较
- 关于编译x264时出现的for Cortex-A8 erratum because it has no mapping symbols问题
- 牙齿讲座记录
- 排序算法之一:冒泡排序和插入排序
- POJ DP训练计划
- Gson的反射解析机制详解(1)
- HDU4944 FSF’s game【因子和】【递推】
- sicily 1139. 电路稳定性
- html的全局属性
- 九度OJ 1085:求root(N, k) (迭代)
- SCP ubuntu下免密码文件传输
- 可重入与线程安全(Reentrancy and Thread-Safety)
- leetcode Sum Root to Leaf Numbers
- 牛客网 | 包含min函数的栈