最近在一直在学习Mybatis的源码,发现了一个对泛型解析很好的工具类TypeParameterResolver。自己也正好恶补下在泛型和Java-Type体系发面的空白。第一次写博文,路人又发现不足和bug处尽情吐槽。😁
java-Type体系
在分析TypeParameterResolver工具类时,必须先要了解Java的Type体系,其主要由 Class,ParameterizedType,GenericArrayType,TypeVariable和一个用来表示通配表达试的WildcardType类型。这些类型都继承Type这个父接口,所以Type接口又是Java所有类型的公共接口。
ParameterizedType
ParameterizedType表示参数化类型(泛型), 比如Map<K, V>, List<V>。本次需要用到的主要方法:
public interface ParameterizedType extends Type {
//获取<>中的实际类型,即类型实参/形参
Type[] getActualTypeArguments();
//获取<>前面的类型,即基本类型
Type getRawType();
...
}
GenericArrayType
GenericArrayType表示参数化类型的数组,即泛型数组,比如T[] List<T>[]。本次需要用到主要方法:
public interface GenericArrayType extends Type {
//获取数组元素的类型,即获取A<T>(A<T>[])或者T(T[] 获取T[](T[][])),每次只能获取,去掉一维的类型
Type getGenericComponentType();
}
TypeVariable
TypeVariable表示类型变量。比如T, K等用来代表指定类型的类型变量。本次需要用到的主要方法:
public interface TypeVariable<D extends GenericDeclaration> extends Type, AnnotatedElement {
//获取形参的上限
Type[] getBounds();
//获取名称,即T,K,V的名称
String getName();
...
}
WildcardType
WildcardType表示通配符表达式的类型 例如 ? extend Double
public interface WildcardType extends Type {
//获取类型的上限(extend)
Type[] getUpperBounds();
//获取类型的下限(super)
Type[] getLowerBounds();
}
Class
Class表示普通类型,即实际类型不带有类型变量的。比如Double,String等,本次需要用到的主要方法:
public final class Class<T> implements java.io.Serializable,
GenericDeclaration,
Type,
AnnotatedElement {
...
/**
* 获取父类类型,如果父类是泛型,则这里返回的是参数化类型ParameterizedType
* class A<L, M>{}
* class B<K> extends A<K, String>{}
* 则通过B.class.getGenericSuperclass(),返回的是 A<K, String>。即继承时传给父类的类型实参
*/
public Type getGenericSuperclass();
//获取实现所有的接口,如果接口是泛型返回的是参数化类型ParameterizedType,返回的getGenericSuperclass一致
public Type getGenericInterfaces();
/**
* 如果Class是泛型,则获取其泛型<>里的参数(类型形参/类型实参)
* class A<L, M>{} 返回的是 [L, M]
*/
public TypeVariable<?>[] getTypeParameters();
...
}
初步了解上面的Type体系,就看看TypeParameterResolver的调用流程和主要方法
TypeParameterResolver 分析
作用
TypeParameterResolver 工具类主要是对Mybatis中需要的类或者接口解析反射时,对其复杂的泛型进行解析保存为其自定义的Type体系接口(TypeParameterResolver中有实现类),对其中的类型形参,使用类型实参表示。然后缓存起来,方便下次使用。
流程介绍
主要方法调用流程图.jpg工具类主要有三个对外开放的方法,分别是resolveFieldType(解析字段的类型),resolveReturnType(解析方法返回类型)和resolveParamTypes(解析方法入参的类型)。三个方法获取到需要解析的类型后,调用resolveType方法进行统一的处理。resolveType方法根据入参的类型的类别,分别调用resolveTypeVar(类型变量解析),resolveParameterizedType(参数化类型解析)和resolveGenericArrayType(泛型数组)解析。
由于一些泛型类型比较复杂比如List<N>[],那最后实际处理的方法会相互递归调用进行解析。
主要方法源码解析
主要入参变量的解释
srcType:被反射时调用的类型,即被解析的方法或字段是通过那个类型反射出来的
declaringClass:定义被解析的方法或字段的class类型,即这个方法/字段是定义在那个class中的
public interface A<N>{
public N getVal();
}
public interface B extends A<String>{}
如上面代码所示,如果通过B接口获取到的getVal方法并对其返回值进行解析,则srcType表示B的类型,declaringClass表示A的类型
resolveFieldType
public static Type resolveFieldType(Field field, Type srcType) {
//获取需要解析的字段类型
Type fieldType = field.getGenericType();
//获取字段定义的类的class
Class<?> declaringClass = field.getDeclaringClass();
//实际解析
return resolveType(fieldType, srcType, declaringClass);
}
resolveReturnType
public static Type resolveReturnType(Method method, Type srcType) {
//获取方法的返回类型
Type returnType = method.getGenericReturnType();
//获取方法定义的类的类型
Class<?> declaringClass = method.getDeclaringClass();
//实际解析
return resolveType(returnType, srcType, declaringClass);
}
resolveParamTypes
public static Type[] resolveParamTypes(Method method, Type srcType) {
//获取方法所有参数类型
Type[] paramTypes = method.getGenericParameterTypes();
//获取方法定义的类类型
Class<?> declaringClass = method.getDeclaringClass();
Type[] result = new Type[paramTypes.length];
for (int i = 0; i < paramTypes.length; i++) {
//对每个参数的类型进行解析
result[i] = resolveType(paramTypes[i], srcType, declaringClass);
}
return result;
}
从上面的代码中可以看出,对外开放的每个方法都只是获取了需要处理的类型变量,实际解析都是交给了resolveType方法
resolveType
private static Type resolveType(Type type, Type srcType, Class<?> declaringClass) {
if (type instanceof TypeVariable) {
//解析TypeVariable类型
return resolveTypeVar((TypeVariable<?>) type, srcType, declaringClass);
} else if (type instanceof ParameterizedType) {
//解析ParameterizedType类型
return resolveParameterizedType((ParameterizedType) type, srcType, declaringClass);
} else if (type instanceof GenericArrayType) {
//解析GenericArrayType类型
return resolveGenericArrayType((GenericArrayType) type, srcType, declaringClass);
} else {
//如果为普通的Class类型就直接返回
return type;
}
}
从上面的代码中可以看出resolveType方法主要是对类型变量的解析的分发。除了普通的Class类型,其它的都有其对应的处理方法进行处理,下面对主要的处理方法进行解释。
resolveParameterizedType
private static ParameterizedType resolveParameterizedType(ParameterizedType parameterizedType, Type srcType, Class<?> declaringClass) {
//获取泛型的基本类型
Class<?> rawType = (Class<?>) parameterizedType.getRawType();
//获取泛型中的类型实参
Type[] typeArgs = parameterizedType.getActualTypeArguments();
//递归处理其类型实参
Type[] args = new Type[typeArgs.length];
for (int i = 0; i < typeArgs.length; i++) {
//判断对应参数的类型,分别进行递归处理
if (typeArgs[i] instanceof TypeVariable) {
//解析TypeVariable类型
args[i] = resolveTypeVar((TypeVariable<?>) typeArgs[i], srcType, declaringClass);
} else if (typeArgs[i] instanceof ParameterizedType) {
//解析ParameterizedType类型
args[i] = resolveParameterizedType((ParameterizedType) typeArgs[i], srcType, declaringClass);
} else if (typeArgs[i] instanceof WildcardType) {
//是解析WildcardType类型(其类型实参是通配符表达式)
args[i] = resolveWildcardType((WildcardType) typeArgs[i], srcType, declaringClass);
} else {
//普通Class类型,直接返回
args[i] = typeArgs[i];
}
}
//返回自定以类型
return new ParameterizedTypeImpl(rawType, null, args);
}
resolveGenericArrayType
private static Type resolveGenericArrayType(GenericArrayType genericArrayType, Type srcType, Class<?> declaringClass) {
//去掉一层[]后的泛型类型变量
Type componentType = genericArrayType.getGenericComponentType();
Type resolvedComponentType = null;
//根据去掉一维数组后的类型变量,在根据其类型递归解析
if (componentType instanceof TypeVariable) {
//如果去掉后为TypeVariable类型,则调用resolveTypeVar方法
resolvedComponentType = resolveTypeVar((TypeVariable<?>) componentType, srcType, declaringClass);
} else if (componentType instanceof GenericArrayType) {
//如果去掉仍为GenericArrayType类型,则递归调用resolveGenericArrayType方法
resolvedComponentType = resolveGenericArrayType((GenericArrayType) componentType, srcType, declaringClass);
} else if (componentType instanceof ParameterizedType) {
//如果去掉后为ParameterizedType类型,则调用resolveParameterizedType方法处理
resolvedComponentType = resolveParameterizedType((ParameterizedType) componentType, srcType, declaringClass);
}
if (resolvedComponentType instanceof Class) {
//如果处理后的结果为基本的Class类型,则返回对应的Class的数组类型(处理N[][])。
return Array.newInstance((Class<?>) resolvedComponentType, 0).getClass();
} else {
//否则包装为自定义的GenericArrayTypeImpl类型
return new GenericArrayTypeImpl(resolvedComponentType);
}
}
通过上面两个方法可以看到,在处理参数化类型和泛型数组时,都是采用递归的模式,一层层的往里解析。直到解析到单独的类型变量或者基础类型为止,再一层层的包装返回。其最后处理一般为通配符类型,类型变量和基本类型。其中基本类型无需处理。主要是TypeVariable类型和WildcardType类型的解析。
resolveTypeVar
/**
* 解析具体的类型变量指代的类型。
* 1.如果srcType的Class类型和declaringClass为同一个类,表示获取该类型变量时被反射的类型就是其定义的类型,则取该类型变量定义是有没有上限,如果有则使用其上限代表其类型,否则就用Object。
* 2.如果不是,则代表declaringClass是srcType的父类或者实现的接口,则解析继承中有没有定义其代表的类型
*/
private static Type resolveTypeVar(TypeVariable<?> typeVar, Type srcType, Class<?> declaringClass) {
Type result = null;
Class<?> clazz = null;
/**
* 判断srcType是否为Class/ParameterizedType类型
* 如果不是这两种类型这抛出异常
*/
if (srcType instanceof Class) {
clazz = (Class<?>) srcType;
} 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());
}
/**
* 如果declaringClass和srcType的实际类型一直则表示无法获取其类型实参。
* 如果typeVar有上限限定则返回其上限,否则返回Object处理
*/
if (clazz == declaringClass) {
Type[] bounds = typeVar.getBounds();
if(bounds.length > 0) {
return bounds[0];
}
return Object.class;
}
/**
*
*/
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
/**
* 通过对父类/接口的扫描获取其typeVar指代的实际类型
*/
private static Type scanSuperTypes(TypeVariable<?> typeVar, Type srcType, Class<?> declaringClass, Class<?> clazz, Type superclass) {
Type result = null;
/*
* 判断处理的父类superclass是否为参数化类型,如果不是则代表declaringClass和superclass的基本Class
* 类型不是同一个类。
*/
if (superclass instanceof ParameterizedType) {
//如果为ParameterizedType,则获取它基本类型
ParameterizedType parentAsType = (ParameterizedType) superclass;
Class<?> parentAsClass = (Class<?>) parentAsType.getRawType();
if (declaringClass == parentAsClass) {
//如果declaringClass和parentAsClass表示同一类型,则通过typeVar在declaringClass的泛型形参的index获取其在supperClass中定义的类型实参
Type[] typeArgs = parentAsType.getActualTypeArguments();
TypeVariable<?>[] declaredTypeVars = declaringClass.getTypeParameters();
for (int i = 0; i < declaredTypeVars.length; i++) {
//循环判断当前处理的类型是否属于所属的类型描述符中的变量
if (declaredTypeVars[i] == typeVar) {
/*
*如果supperClass中定义的类型形参还是类型变量则取srcType中的类型形参的定义
* 如果srcType中的类型形参还是类型变量则不处理。
*/
if (typeArgs[i] instanceof TypeVariable) {
//其子类中的所有泛型描述符
TypeVariable<?>[] typeParams = clazz.getTypeParameters();
for (int j = 0; j < typeParams.length; j++) {
if (typeParams[j] == typeArgs[i]) {
//判断是否为ParameterizedType,则去实际代表的类型
if (srcType instanceof ParameterizedType) {
result = ((ParameterizedType) srcType).getActualTypeArguments()[j];
}
break;
}
}
} else {
//如果不是TypeVariable,直接取对应的类型
result = typeArgs[i];
}
}
}
} else if (declaringClass.isAssignableFrom(parentAsClass)) {
//通过判断superclass是否是declaringClass的子类(由于java类可以实现多个接口),进行递归解析
result = resolveTypeVar(typeVar, parentAsType, declaringClass);
}
} else if (superclass instanceof Class) {
//如果superclass为Class类型,通过判断superclass是否是declaringClass的子类(由于java类可以实现多个接口),进行递归解析
if (declaringClass.isAssignableFrom((Class<?>) superclass)) {
result = resolveTypeVar(typeVar, superclass, declaringClass);
}
}
return result;
}
通过对resolveTypeVar和scanSuperTypes的分析了解到。在解析基本的类型变量时其主要在被反射类和其定义类的继承路线中是否有明确制定其实际类型,如果有则使用制定了的类型。如果被反射类和其定义类是同一个,则取类型变量的上限或者Object类表示。由于在最后其实际类型时只回溯到其定义类的第二层子类,所以自能判断到其到第二层子类的实际类型的指定
resolveWildcardType
private static Type resolveWildcardType(WildcardType wildcardType, Type srcType, Class<?> declaringClass) {
//获取下限
Type[] lowerBounds = resolveWildcardTypeBounds(wildcardType.getLowerBounds(), srcType, declaringClass);
//获取上限
Type[] upperBounds = resolveWildcardTypeBounds(wildcardType.getUpperBounds(), srcType, declaringClass);
//包装成自定义的WildcardTypeImpl类型返回
return new WildcardTypeImpl(lowerBounds, upperBounds);
}
在对通配符进行解析时,主要对其上下限的类型进行解析
resolveWildcardTypeBounds
private static Type[] resolveWildcardTypeBounds(Type[] bounds, Type srcType, Class<?> declaringClass) {
Type[] result = new Type[bounds.length];
for (int i = 0; i < bounds.length; i++) {
//根据上下限不同的类型,进行解析
if (bounds[i] instanceof TypeVariable) {
result[i] = resolveTypeVar((TypeVariable<?>) bounds[i], srcType, declaringClass);
} else if (bounds[i] instanceof ParameterizedType) {
result[i] = resolveParameterizedType((ParameterizedType) bounds[i], srcType, declaringClass);
} else if (bounds[i] instanceof WildcardType) {
result[i] = resolveWildcardType((WildcardType) bounds[i], srcType, declaringClass);
} else {
result[i] = bounds[i];
}
}
return result;
}
对其上下限进行解析时,主要根据其不同的类型调用上面的以有解析方法进行递归解析
网友评论