Gson是如何在运行时处理字段的泛型信息
来源:互联网 发布:windows boot manager 编辑:程序博客网 时间:2024/05/16 11:32
在《Gson是如何记录泛型信息的》一文中,讲述了Gson是如何通过特定的方式记录下序列化处理过程中的泛型信息。那么,在序列化的过程中,又是如何进行泛型信息的处理的?比如在处理Map类型中,该如何找到key和value的实际类型。
class Map<K, V> { K key; V value;}
在《Gson是如何记录泛型信息的》一文的基础上,我们已经获得到rawType以及type。
思考反序列化的过程,我们需要处理反序列化目标类型中的每一个字段。假设遇到某一字段Field,此时Gson通过$Gson$Types的resolve()函数进行处理。resolve()函数处理字段类型中的泛型信息,将其转化为实际类型。
// 反序列过程中的执行语句 Type fieldType = $Gson$Types.resolve(type.getType(), raw, field.getGenericType()); // resolve函数 public static Type resolve(Type context, Class<?> contextRawType, Type toResolve) { while (true) { if (toResolve instanceof TypeVariable) { TypeVariable<?> typeVariable = (TypeVariable<?>) toResolve; toResolve = resolveTypeVariable(context, contextRawType, typeVariable); if (toResolve == typeVariable) { return toResolve; } } else if (toResolve instanceof Class && ((Class<?>) toResolve).isArray()) { Class<?> original = (Class<?>) toResolve; Type componentType = original.getComponentType(); Type newComponentType = resolve(context, contextRawType, componentType); return componentType == newComponentType ? original : arrayOf(newComponentType); } else if (toResolve instanceof GenericArrayType) { GenericArrayType original = (GenericArrayType) toResolve; Type componentType = original.getGenericComponentType(); Type newComponentType = resolve(context, contextRawType, componentType); return componentType == newComponentType ? original : arrayOf(newComponentType); } else if (toResolve instanceof ParameterizedType) { ParameterizedType original = (ParameterizedType) toResolve; Type ownerType = original.getOwnerType(); Type newOwnerType = resolve(context, contextRawType, ownerType); boolean changed = newOwnerType != ownerType; Type[] args = original.getActualTypeArguments(); for (int t = 0, length = args.length; t < length; t++) { Type resolvedTypeArgument = resolve(context, contextRawType, args[t]); if (resolvedTypeArgument != args[t]) { if (!changed) { args = args.clone(); changed = true; } args[t] = resolvedTypeArgument; } } return changed ? newParameterizedTypeWithOwner(newOwnerType, original.getRawType(), args) : original; } else if (toResolve instanceof WildcardType) { WildcardType original = (WildcardType) toResolve; Type[] originalLowerBound = original.getLowerBounds(); Type[] originalUpperBound = original.getUpperBounds(); if (originalLowerBound.length == 1) { Type lowerBound = resolve(context, contextRawType, originalLowerBound[0]); if (lowerBound != originalLowerBound[0]) { return supertypeOf(lowerBound); } } else if (originalUpperBound.length == 1) { Type upperBound = resolve(context, contextRawType, originalUpperBound[0]); if (upperBound != originalUpperBound[0]) { return subtypeOf(upperBound); } } return original; } else { return toResolve; } } }
在上述代码中,单独一行是反序列化过程中对字段类型的处理语句。其中field.getGenericType返回字段的泛型类型。在resolve()函数,则枚举进行处理字段的各种可能类型。以下类中的各字段代表resolve()中处理的各种类型。
public class Result<T> { // TypeVariable类型,需要找到T的实际类型 T succ; // 数组类型 Integer[] integers; // GenericArrayType类型 T[] ts; // ParameterizedType类型 List<T> list; ...}
接着拆开阐述resolve中各种类型的处理过程。
1.TypeVariable类型的处理
if (toResolve instanceof TypeVariable) { TypeVariable<?> typeVariable = (TypeVariable<?>) toResolve; // 处理过程 toResolve = resolveTypeVariable(context, contextRawType, typeVariable); if (toResolve == typeVariable) { return toResolve; } }
在TypeVariable类型的处理过程中,resolveTypeVariable()函数封装了整个处理,用来找到TypeVariable变量的实际类型。
static Type resolveTypeVariable(Type context, Class<?> contextRawType, TypeVariable<?> unknown) { // 找到泛型变量声明的类型 Class<?> declaredByRaw = declaringClassOf(unknown); // we can't reduce this further if (declaredByRaw == null) { return unknown; } // 获得带有泛型实际类型的类 Type declaredBy = getGenericSupertype(context, contextRawType, declaredByRaw); if (declaredBy instanceof ParameterizedType) { // 查询泛型变量在declaredByRaw中声明的位置 int index = indexOf(declaredByRaw.getTypeParameters(), unknown); // 根据泛型变量声明的位置返回实际类型 return ((ParameterizedType) declaredBy).getActualTypeArguments()[index]; } return unknown; } /** * 查找泛型变量在哪个类进行声明的 */ private static Class<?> declaringClassOf(TypeVariable<?> typeVariable) { GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration(); return genericDeclaration instanceof Class ? (Class<?>) genericDeclaration : null; } /** * 返回带有泛型实际类型信息的类型 */ static Type getGenericSupertype(Type context, Class<?> rawType, Class<?> toResolve) { if (toResolve == rawType) { return context; } // we skip searching through interfaces if unknown is an interface // 在resolveTypeVariable调用该函数之前,如果toResolve是接口,在直接返回了 if (toResolve.isInterface()) { Class<?>[] interfaces = rawType.getInterfaces(); for (int i = 0, length = interfaces.length; i < length; i++) { if (interfaces[i] == toResolve) { return rawType.getGenericInterfaces()[i]; } else if (toResolve.isAssignableFrom(interfaces[i])) { return getGenericSupertype(rawType.getGenericInterfaces()[i], interfaces[i], toResolve); } } } // check our supertypes if (!rawType.isInterface()) { while (rawType != Object.class) { Class<?> rawSupertype = rawType.getSuperclass(); if (rawSupertype == toResolve) { return rawType.getGenericSuperclass(); } else if (toResolve.isAssignableFrom(rawSupertype)) { return getGenericSupertype(rawType.getGenericSuperclass(), rawSupertype, toResolve); } rawType = rawSupertype; } } // we can't resolve this further return toResolve; }
从上面可以看到,resolveTypeVariable()处理泛型信息的步骤如下:
1. 获得字段声明的类(因为字段有可能是在父类或父接口中声明的)
2. 通过getSuperClass()和getGenericSuperclass()查找带有泛型实参的类
3. 获得泛型形参在类中声明的索引
4. 通过该索引在带有泛型实参的类中找到泛型的实际参数类型
2.数组类型的处理
resolve()函数对数组的处理关键是找到数组参数的实际类型。
if (toResolve instanceof Class && ((Class<?>) toResolve).isArray()) { Class<?> original = (Class<?>) toResolve; Type componentType = original.getComponentType(); // 获得数组元素的实际类型 Type newComponentType = resolve(context, contextRawType, componentType); // 返回 return componentType == newComponentType ? original : arrayOf(newComponentType); }
3.GenericArrayType类型的处理
可以看到,对于泛型数组的处理的关键同样是找到泛型数组元素的实际类型。
if (toResolve instanceof GenericArrayType) { GenericArrayType original = (GenericArrayType) toResolve; Type componentType = original.getGenericComponentType(); // 获得数组元素的实际类型 Type newComponentType = resolve(context, contextRawType, componentType); return componentType == newComponentType ? original : arrayOf(newComponentType);}
4.ParameterizedType类型的处理
在ParameterizedType类型处理中,有两个泛型信息需要处理,分别是ownerType和泛型参数,同样通过递归调用resolve()方法解决。
if (toResolve instanceof ParameterizedType) { ParameterizedType original = (ParameterizedType) toResolve; Type ownerType = original.getOwnerType(); // 处理ownerType的泛型 Type newOwnerType = resolve(context, contextRawType, ownerType); boolean changed = newOwnerType != ownerType; Type[] args = original.getActualTypeArguments(); for (int t = 0, length = args.length; t < length; t++) { // 处理ParameterizedType中的泛型类型 Type resolvedTypeArgument = resolve(context, contextRawType, args[t]); if (resolvedTypeArgument != args[t]) { if (!changed) { args = args.clone(); changed = true; } args[t] = resolvedTypeArgument; } } // 返回类型转化之后的对象 return changed ? newParameterizedTypeWithOwner(newOwnerType, original.getRawType(), args) : original; }
5.WildcardType类型的处理
对于通配符类型,需要处理是通配符的上界和下界,处理方法采用递归调用resolve(),此处不再详细展开。
总结:
在Gson进行序列化/反序列的过程中,如何正确地找到字段定义的泛型参数类型是比较重要的一个步骤。不管是ParameterizedType、还是GenericArrayType类型,其最终需要处理的都是TypeVariable类型。在完成TypeVariable解析之后,都可以通过递归的方法解析出其他几种字段类型。TypeVariable类型解析的主要步骤如下:
1. 获得字段声明的类(因为字段有可能是在父类或父接口中声明的)
2. 通过getSuperClass()和getGenericSuperclass()查找带有泛型实参的类
3. 获得泛型形参在类中声明的索引
4. 通过该索引在带有泛型实参的类中找到泛型的实际参数类型
- Gson是如何在运行时处理字段的泛型信息
- Gson是如何记录泛型信息的
- 如何处理数据库字段是bigint型?
- Gson解析时,在返回相同的实体,但对应的字段不同(可能是不同部门的api)
- Gson字段特殊处理
- 类在运行时是如何构造生成的
- 类在运行时是如何构造生成的
- 利用gson处理Java反射TypeToken泛型运行时类型擦除
- Gson解析时对于不确定泛型的处理
- gson处理泛型的问题
- ASPxGridView如何在运行时根据列的字段名查找一个列
- 如何在oracle 加个自动增加的字段(指的是字段值)
- Samza的Task是如何运行在Yarn上的
- 如何在运行时获取泛型的类型
- 下载烧录后, 如何判定程序是在运行的呢?
- 一个程序在计算机中到底是如何运行的?
- 一个程序在计算机中到底是如何运行的?
- 一个程序在计算机中到底是如何运行的?
- arm第二天(环境搭建、LED上)
- HC-06蓝牙模块设置与使用
- 苹果手机不显示图片的解决方法
- 游戏中使用LUA脚本语言的简介
- 数据库事务与锁的关系
- Gson是如何在运行时处理字段的泛型信息
- 11.28 北京,念腾讯暑假,不思则惘吧!
- php--异常处理
- Alibaba-Dexposed Bug框架原理及源码解析
- 江苏省职业健康监护平台数据交换方案
- Centos的yum源更换为国内的阿里云源
- TODO:一不顺眼就换字体Go之代码篇
- Vigenere Decode
- ReactNative的Navigator组件使用方式