MyBatis源码实现之反射工具箱TypeParameterResolver
反射工具箱之TypeParameterResolver
Type
在开始介绍TypeParameterResolver 之前,先简单介绍一下Type接口的基础知识。Type 是
所有类型的父接口,它有四个子接口和一个实现类,如图2-10 所示。
下面来看这些子接口和子类所代表的类型。
- Class 比较常见,它表示的是原始类型。Class 类的对象表示NM 中的一个类或接口,
每个Java 类在NM 里都表现为一个Class 对象。在程序中可以通过“类名.class ”、“对
象.getClass()”或是“Class.forName(‘类名’)”等方式获取class对象。数组也被映射成
Class 对象,所有元素类型相同且维数相同的数组都共享同一个Class 对象。 ParameterizedType 表示的是参数化类型,例如List<String> 、Map<Integer,String>、
Service<User>这种带有泛型的类型。
ParameterizedType 接口中常用的方法有三个,分别是:- Type getRawType ()一一返回参数化类型中的原始类型,例如List<String > 的原始类
型为List 。 - Type[] getActualTypeArguments ()一一获取参数化类型的类型变量或是实际类型列
表,例如Map<Integer, String> 的实际泛型列表Integer 和String 。需要注意的是,
该列表的元素类型都是Type ,也就是说,可能存在多层嵌套的情况。 - Type getOwnerType ()一一返回是类型所属的类型,例如存在A类,其中定义了
内部类InnerA
接口是Map.Entry<K,V >接口的所有者。
- Type getRawType ()一一返回参数化类型中的原始类型,例如List<String > 的原始类
TypeVariable 表示的是类型变量,它用来反映在JVM编译该泛型前的信息。例如List
中的T就是类型变量,它在编译时需被转换为一个具体的类型后才能正常使用。
该接口中常用的方法有三个,分别是:- Type[] getBounds ()一一获取类型变量的上边界,如果未明确声明上边界则默认为
Object 。例如class Test<K extends Person > 中K 的上界就是Person 。 - D getGenericDeclaration()一一获取声明该类型变量的原始类型,例如class Test<K
extends Person>中的原始类型是Test 。 - String getNameO 一一获取在源码中定义时的名字,上例中为K 。
- Type[] getBounds ()一一获取类型变量的上边界,如果未明确声明上边界则默认为
- GenericArrayType 表示的是数组类型且组成元素是ParameterizedType 或TypeVariable .
例如List<String>[]或T[] 。该接口只有Type getGenericComponentType () 一个方法,它
返回数组的组成元素。 WildcardType 表示的是通配符泛型,例如? extends Number 和? super Integer 。
WildcardType 接口有两个方法,分别是:- Type[] getUpperBounds ()一一-返回泛型变量的上界。
- Type[] getLowerBounds()一-返回泛型变量的下界。
TypeParameterResolver
介绍完Type接口的基础知识,我们回到对TypeParameterResolver 介绍。在对Reflector的
分析过程中,我们看到了TypeParameterResolver 的身影,它是一个工具类,提供了一系列静态
方法来解析指定类中的宇段、方法返回值或方法参数的类型。TypeParameterResolver 中各个静
态方法之间的调用关系大致如图2-11 所示,为保持清晰,其中递归调用没有表现出来,在后面
的代码分析过程中会进行强调。
TypeParameterResolver 中通过resolveFieldType ()方法、resolveReturnType () 方法、
resolveParamTypes ()方法分别解析宇段类型、方法返回值类型和方法参数列表中各个参数的类型。
这三个方法的逻辑基本类似,这里以resolveFieldType ()方法为例进行介绍,剩余两个方法请读
者参考源码学习。TypeParameterResolver.resolveFieldType ()方法的具体实现如下:
public static Type resolveFieldType(Field field, Type srcType) {
// 获取字段的声明类型
Type fieldType = field.getGenericType();
// 获取字段定义所在类的Class对象
Class<?> declaringClass = field.getDeclaringClass();
// 调用resolveType进行后续处理
return resolveType(fieldType, srcType, declaringClass);
}
注:
getType(): 获取属性声明时类型对象(返回class对象)
getGenericType() : 返回属性声的Type类型
getType() 和 getGenericType()的区别 :
1.首先是返回的类型不一样,一个是Class对象一个是Type接口。
2.如果属性是一个泛型,从getType()只能得到这个属性的接口类型。但从getGenericType()还能得到这个泛型的参数类型。
3.getGenericType()如果当前属性有签名属性类型就返回,否则就返回 Field.getType()。
如图2-11所示,上述三个方法都会调用resolveType() 方法,该方法会根据其第一个参数的
类型,即字段、方法返回值或方法参数的类型,选择合适的方法进行解析。resolveType()方法的
第二个参数表示查找该字段、返回值或方法参数的起始位置。第三个参数则表示该字段、方法
定义所在的类。TypeParameterResolver.resolveType()方法代码如下:
private static Type resolveType(Type type, Type srcType, Class<?> declaringClass) {
if (type instanceof TypeVariable) {
// 解析TypeVariable类型(JVM编译该泛型前的信息。例如List<T>)
return resolveTypeVar((TypeVariable<?>) type, srcType, declaringClass);
} else if (type instanceof ParameterizedType) {
// 解析ParameterizedType类型(表示的是参数化类型,例如List<String>)
return resolveParameterizedType((ParameterizedType) type, srcType, declaringClass);
} else if (type instanceof GenericArrayType) {
// 解析GenericArrayType(数组类型且组成元素是ParameterizedType 或TypeVariable .
// 例如List<String>[]或T[] )
return resolveGenericArrayType((GenericArrayType) type, srcType, declaringClass);
} else {
// Class类型
return type;
}
// 字段、返回值、参数不可能直接定义成WildcardType 类型,但可以嵌套在别的类型中,后面会分析到
}
为了读者便于理解,这里通过一个示例分析resolveType()方法,假设有三个类一-ClassA 、
SubClassA 、TestType ,代码如下:
import com.sun.org.apache.xerces.internal.dom.PSVIAttrNSImpl;
import org.apache.ibatis.reflection.TypeParameterResolver;
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
class classA<K, V> {
protected HashMap<K, V> map;
public HashMap<K, V> getMap() {
return map;
}
public void setMap(HashMap<K, V> map) {
this.map = map;
}
}
class SubClassA<T> extends classA<T, T>{}
class TestType {
SubClassA<Long> aa = new SubClassA<>();
public static void main(String[] args) throws Exception {
Field field = classA.class.getDeclaredField("map");
System.out.println(field.getGenericType());
System.out.println(field.getGenericType() instanceof ParameterizedType);
System.out.println("-----------------------------");
// 解析SubA<Long> ( ParameterizedType 类型)中的map 字段,注意: ParameterizedTypeimpl 是
// 在sun.reflect.generics.reflectObjects包下的ParameterizedType 接口实现
Type type = TypeParameterResolver.resolveFieldType(field, ParameterizedTypeImpl.make(SubClassA.class, new Type[]{Long.class}, TestType.class));
System.out.println(type.getClass());
System.out.println(type);
// 输出:class org.apache.ibatis.reflection.TypeParameterResolver$ParameterizedTypeImpl
// 注意, TypeParameterResolver$ParameterizedTypeImpl是ParameterizedType 接口的实现
// ~~~
// 也可以使用下面的方式生成上述ParameterizedType 对象,
// 并调用TypeParameterResolver.resolveFieldType ()方法:
// Type aaa = TestType.class.getDeclaredField("aa").getGenericType();
// // com.gyoomi.parameterresolver.SubClassA<java.lang.Long>
// Type type2 = TypeParameterResolver.resolveFieldType(field, TestType.class.getDeclaredField("aa").getGenericType());
// System.out.println(type2);
// ~~~
ParameterizedType pType = (ParameterizedType) type;
System.out.println(pType);
System.out.println("----------------------------");
System.out.println("rawType:" + pType.getRawType());
System.out.println("ownerType:" + pType.getOwnerType());
Type[] actualTypeArguments = pType.getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
根据前面对Type 接口的介绍,上例中ClassA.map 字段声明的类型Map<K,V>是
ParameterizedType类型,resolveType()方法会调用resolveParameterizedType()方法进行解析。首
先介绍resolveParameterizedType()方法的参数: 第一个参数是待解析的ParameterizedType 类型;
第二个参数是解析操作的起始类型:第三个参数为定义该字段或方法的类的Class 对象。在该
示例中第一个参数是Map<K,V>对应的ParameterizedType 对象,第二个参数是
TypeText.SubA <Long>对应的ParameterizedType 对象,第三个参数是ClassA (声明map 字段的
类)相应的Class 对象。TypeParameterResolver.resolveParameterizedType ()方法代码如下:
private static ParameterizedType resolveParameterizedType(ParameterizedType parameterizedType, Type srcType, Class<?> declaringClass) {
// 在该示例中,得到的原始类型class对象
Class<?> rawType = (Class<?>) parameterizedType.getRawType();
// 类型变量为K、V
Type[] typeArgs = parameterizedType.getActualTypeArguments();
// 用来保存解析后的结果
Type[] args = new Type[typeArgs.length];
// 循环解析K, V
for (int i = 0; i < typeArgs.length; i++) {
if (typeArgs[i] instanceof TypeVariable) { // 类型变量,JVM编译前的类型
args[i] = resolveTypeVar((TypeVariable<?>) typeArgs[i], srcType, declaringClass);
} else if (typeArgs[i] instanceof ParameterizedType) { // 泛型化的参数类型
// 如果嵌套了ParameterizedType ,则调用resolveParameterizedType ()方法进行处理
args[i] = resolveParameterizedType((ParameterizedType) typeArgs[i], srcType, declaringClass);
} else if (typeArgs[i] instanceof WildcardType) { // 通配符的参数类型
// 如果嵌套了WildcardType ,则调用resolveWildcardType()方法进行处理
args[i] = resolveWildcardType((WildcardType) typeArgs[i], srcType, declaringClass);
} else { // Class类型
args[i] = typeArgs[i];
}
}
// TypeParameterResolver.ParameterizedTypeImpl是当前类一个内部类
// 将解析结果封装成TypeParameterResolver 中定义的Parameter工zed Type 实现并返回,本例中args
// 数组中的元素都是Long.class
return new ParameterizedTypeImpl(rawType, null, args);
}
TypeParameterResolver.resolveTypeVar()方法负责解析TypeVariable ,本例会调用该方法解析
SubClassA.map字段的K和V。在该示例中,第一个参数是类型变量K 对应的TypeVariable对
象,第二个参数依然是TypeText.SubA<Long>对应的ParameterizedType对象,第三个参数是
ClassA(声明map 字段的类)对应的Class对象。TypeParameterResolver.resolveTypeVar()方法的
具体实现如下:
private static Type resolveTypeVar(TypeVariable<?> typeVar, Type srcType, Class<?> declaringClass) {
Type result = null;
Class<?> clazz = null;
if (srcType instanceof Class) {
clazz = (Class<?>) srcType;
// 本例中SubA<Long>是ParameterizedType类型,clazz为SubClassA对应的Class对象
} else if (srcType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) srcType;
clazz = (Class<?>) parameterizedType.getRawType();
} else {
throw new IllegalArgumentException("The 2nd arg must be Class or ParameterizedType, but was: " + srcType.getClass());
}
// 因为SubClassA 继承了ClassA且map 字段定义在ClassA 中,故这里的srcType与declaringClass
// 并不相等。如果map 字段定义在SubClassA中,则可以直接结束对K的解析
if (clazz == declaringClass) {
Type[] bounds = typeVar.getBounds();
if(bounds.length > 0) {
return bounds[0];
}
return Object.class;
}
// 获取声明的父类类型,即ClassA<T,T >对应的ParameterizedType对象
Type superclass = clazz.getGenericSuperclass();
// 通过扫描父类进行后续解析,这是递归的入口
result = scanSuperTypes(typeVar, srcType, declaringClass, clazz, superclass);
if (result != null) {
return result;
}
// 获取接口
Type[] superInterfaces = clazz.getGenericInterfaces();
for (Type superInterface : superInterfaces) {
// 通过扫描接口进行后续解析,逻辑同扫描父类(略)
result = scanSuperTypes(typeVar, srcType, declaringClass, clazz, superInterface);
if (result != null) {
return result;
}
}
// 若在整个继承结构中都没有解析成功,则返回Object.class
return Object.class;
}
我们继续分析scanSuperTypes()方法,该方法会递归整个继承结构井完成类型变量的解析。
在该示例之中,第一个参数是K对应的TypeVariable 对象,第二个参数是TypeText.SubA
对应的ParameterizedType 对象,第三个参数是ClassA(声明map字段的类)对应的Class 对象,
第四个参数是SubClassA 对应的Class 对象,第五个参数是Class
对象。scanSuperTypes ()方法的具体实现如下:
private static Type scanSuperTypes(TypeVariable<?> typeVar, Type srcType, Class<?> declaringClass, Class<?> clazz, Type superclass) {
Type result = null;
// superclass 是ClassA<T ,T >对应的ParameterizedType 对象,条件成立
if (superclass instanceof ParameterizedType) {
ParameterizedType parentAsType = (ParameterizedType) superclass;
// 原始类型是classA
Class<?> parentAsClass = (Class<?>) parentAsType.getRawType();
// map字段定义在classA类中条件成立
if (declaringClass == parentAsClass) {
// {T, T}
Type[] typeArgs = parentAsType.getActualTypeArguments();
// 在classA中定义的类型变量K, V
TypeVariable<?>[] declaredTypeVars = declaringClass.getTypeParameters();
for (int i = 0; i < declaredTypeVars.length; i++) {
// 解析的目标类型是K
if (declaredTypeVars[i] == typeVar) {
if (typeArgs[i] instanceof TypeVariable) { // T是类型变量,条件成立
// SubClassA 只有一个类型交量T,且声明的父类是ClassA<T ,T >,本例中T被参数化为Long,则K参数化为Long
TypeVariable<?>[] typeParams = clazz.getTypeParameters();
for (int j = 0; j < typeParams.length; j++) {
if (typeParams[j] == typeArgs[i]) {
if (srcType instanceof ParameterizedType) {
result = ((ParameterizedType) srcType).getActualTypeArguments()[j];
}
break;
}
}
} else {
// 如果SubClassA 继承了ClassA<Long, Long >,则typeArgs[i]不是TypeVariable 类型,直接返回Long.class
result = typeArgs[i];
}
}
}
} else if (declaringClass.isAssignableFrom(parentAsClass)) { // 继续解析父类,直到解析到定义该字段的类
result = resolveTypeVar(typeVar, parentAsType, declaringClass);
}
} else if (superclass instanceof Class) { // 声明的父类不再含有类型变量且不是定义该字段的类,则继续解析
if (declaringClass.isAssignableFrom((Class<?>) superclass)) {
result = resolveTypeVar(typeVar, superclass, declaringClass);
}
}
return result;
}
为了便于读者理解scanSuperTypes ()方法的功能,图2-12 展示了scanSuperTypes()方法解析
类型变量的核心逻辑。
介绍完TypeParameterResolver.resolveTypeVar()和resolveParameterizedType() 两个方法之后,
再来看resolveGenericArrayType()方法,该方法负责解析GenericArrayType 类型的变量,它会根
据数组元素的类型选择合适的resolve *()方法进行解析,具体实现如下:
private static Type resolveGenericArrayType(GenericArrayType genericArrayType, Type srcType, Class<?> declaringClass) {
// 获取数纽元素的类型
Type componentType = genericArrayType.getGenericComponentType();
Type resolvedComponentType = null;
if (componentType instanceof TypeVariable) {
// resolveTypeVar()方法已经介绍过了,不再赘述
resolvedComponentType = resolveTypeVar((TypeVariable<?>) componentType, srcType, declaringClass);
} else if (componentType instanceof GenericArrayType) {
// 逆归调用resolveGenericArrayType() 方法
resolvedComponentType = resolveGenericArrayType((GenericArrayType) componentType, srcType, declaringClass);
} else if (componentType instanceof ParameterizedType) {
// resolveParameterizedType ()方法已经介绍过了,不再赘述
resolvedComponentType = resolveParameterizedType((ParameterizedType) componentType, srcType, declaringClass);
}
// 根据解析后的数组项类型构造返回类型
if (resolvedComponentType instanceof Class) {
return Array.newInstance((Class<?>) resolvedComponentType, 0).getClass();
} else {
return new GenericArrayTypeImpl(resolvedComponentType);
}
}
最后我们来看一下TypeParameterResolver.resolveWildcardType ()方法,该方法负责解析
WildcardType 类型的变量。它首先解析WildcardType 中记录的上下界,然后通过解析后的结果
构造WildcardTypeImpl对象返回。具体解析过程与上述resolve*()方法类似,不再贴出代码了。
通过前面的分析可知,当存在复杂的继承关系以及泛型定义时,TypeParameterResolver 可
以帮助我们解析字段、方法参数或方法返回值的类型,这是前面介绍的Reflector类的基础。
另外,MyBatis 源代码中提供了TypeParameterResolverTest 这个测试类,其中从更多角度测
试了TypeParameterResolver的功能,感兴趣的读者可以参考该测试类的实现,可以更全面地了
解TypeParameterResolver的功能。
还没有评论,来说两句吧...