TypeParameterResolver简介
TypeParameterResolver是反射包下的一个工具类,用于解析方法的参数、返回类型和类中定义的字段的类型。
在阅读本片文章之前最好还是先了解一下java.lang.reflcet包下的Type接口及其子接口和实现,关于Type接口的介绍请移步
TypeParameterResolver类中只有三个public方法
- Type resolveFieldType(Field field, Type srcType) :解析字段的类型
- Type resolveReturnType(Method method, Type srcType) : 解析方法返回的类型
- Type[] resolveParamTypes(Method method, Type srcType) : 解析方法参数的类型,因为方法参数可能有多个,故返回一个Type类型的数组
resolveFieldType
//解析字段类型
public static Type resolveFieldType(Field field, Type srcType) {
//获取字段的类型
Type fieldType = field.getGenericType();
//获取定义该字段的类
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;
}
三个方法形参中的Type srcType表示的是起始类型
举例,下面定义了三个接口,Level0Mapper、Level1Mapper和Level2Mapper,这个例子在后面会一直用到。
public interface Level0Mapper<L, M, N> {
List<Calculator<L>> selectCalculatorList();
}
public interface Level1Mapper<E, F> extends Level0Mapper<E, F, String> {}
public interface Level2Mapper extends Level1Mapper<Date, Integer> {}
三个接口的继承关系如下图:
情况1:如果此时要解析Level0Mapper#selectCalculatorList()方法的返回值类型,那么这时的srcType为Level0Mapper。
情况2:如果此时要解析Level1Mapper#selectCalculatorList()方法的返回值类型,那么这时的srcType为Level1Mapper。
情况3:如果此时要解析Level2Mapper#selectCalculatorList()方法的返回值类型,那么这时的srcType为Level2Mapper。
srcType不同直接影响着最后的解析结果,同是对selectCalculatorList方法返回类型的解析:
上述情况1解析后L对应的实际类型为Object
上述情况2解析后L对应的实际类型为E
上述情况3解析后L对应的实际类型为Date
这里准备了三个测试类,分别对应于上面讲的三种情况,如果对上面srcType不是很理解的话,可以debug下面三个测试类帮助理解。
/**
* 测试情况1
* @throws NoSuchMethodException
*/
@Test
void testSituation1() throws NoSuchMethodException {
Class<?> clazz = Level0Mapper.class;
Method method = clazz.getMethod("selectCalculatorList");
Type result = TypeParameterResolver.resolveReturnType(method, clazz);
ParameterizedType paramTypeOuter = (ParameterizedType) result;
ParameterizedType paramTypeInner = (ParameterizedType) paramTypeOuter.getActualTypeArguments()[0];
System.out.println(paramTypeInner.getActualTypeArguments()[0]);
}
/**
* 测试情况2
* @throws NoSuchMethodException
*/
@Test
void testSituation2() throws NoSuchMethodException {
Class<?> clazz = Level1Mapper.class;
Method method = clazz.getMethod("selectCalculatorList");
Type result = TypeParameterResolver.resolveReturnType(method, clazz);
ParameterizedType paramTypeOuter = (ParameterizedType) result;
ParameterizedType paramTypeInner = (ParameterizedType) paramTypeOuter.getActualTypeArguments()[0];
System.out.println(paramTypeInner.getActualTypeArguments()[0]);
}
/**
* 测试情况3
* @throws NoSuchMethodException
*/
@Test
void testSituation3() throws NoSuchMethodException {
Class<?> clazz = Level2Mapper.class;
Method method = clazz.getMethod("selectCalculatorList");
Type result = TypeParameterResolver.resolveReturnType(method, clazz);
ParameterizedType paramTypeOuter = (ParameterizedType) result;
ParameterizedType paramTypeInner = (ParameterizedType) paramTypeOuter.getActualTypeArguments()[0];
System.out.println(paramTypeInner.getActualTypeArguments()[0]);
}
回到三个公有方法中,三个方法的最后都调用了resolveType方法进行解析,下面开始分析resolveType方法。
resolveType
resolveType方法的逻辑很简单,他的作用类似于springmvc框架的前端控制器DispatcherServlet,用于对类型变量的解析的分发。
private static Type resolveType(Type type, Type srcType, Class<?> declaringClass) {
if (type instanceof TypeVariable) {
//解析类型变量
return resolveTypeVar((TypeVariable<?>) type, srcType, declaringClass);
} else if (type instanceof ParameterizedType) {
//解析参数类型
return resolveParameterizedType((ParameterizedType) type, srcType, declaringClass);
} else if (type instanceof GenericArrayType) {
//解析泛型数组
return resolveGenericArrayType((GenericArrayType) type, srcType, declaringClass);
} else {
//Class类型,不需要解析,直接返回即可
return type;
}
}
以上述情况3为例讲解参数类型ParameterizedType的解析和类型变量TypeVar的解析。
resolveParameterizedType
表示解析参数类型,此方法是一个递归方法,解析完外层ParameterizedType后会继续调用相应的方法解析。
本例中会递归调用两次resolveParameterizedType方法,将List<Calculator< L >> —> L,,当第二次进入时当前待解析的类型为类型变量L,此时会调用resolveTypeVar方法进行解析
private static ParameterizedType resolveParameterizedType(ParameterizedType parameterizedType, Type srcType, Class<?> declaringClass) {
//声明此类型的类或接口
Class<?> rawType = (Class<?>) parameterizedType.getRawType();
//此类型实际类型参数的 Type 对象的数组
Type[] typeArgs = parameterizedType.getActualTypeArguments();
Type[] args = new Type[typeArgs.length];
//对typeArgs中的类型逐一进行解析
for (int i = 0; i < typeArgs.length; i++) {
if (typeArgs[i] instanceof TypeVariable) {
args[i] = resolveTypeVar((TypeVariable<?>) typeArgs[i], srcType, declaringClass);
} else if (typeArgs[i] instanceof ParameterizedType) {
args[i] = resolveParameterizedType((ParameterizedType) typeArgs[i], srcType, declaringClass);
} else if (typeArgs[i] instanceof WildcardType) {
args[i] = resolveWildcardType((WildcardType) typeArgs[i], srcType, declaringClass);
} else {
args[i] = typeArgs[i];
}
}
return new ParameterizedTypeImpl(rawType, null, args);
}
resolveTypeVar
resolveTypeVar方法用于解析类型变量,该方法的作用是以srcType为起点,递归向上查找所有的父类或者父接口确定类型参数的实际类型。
/**
*
* @param typeVar 待解析的类型变量
* @param srcType 来源类型
* @param declaringClass 声明typeVar的类
* @return
*/
private static Type resolveTypeVar(TypeVariable<?> typeVar, Type srcType, Class<?> declaringClass) {
Type result;
Class<?> clazz;
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());
}
//如果当前类就是声明方法的类,则直接获取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
return Object.class;
}
scanSuperTypes
该类的作用是以srcType为起点,递归向上查找所有的父类,用于确定类型变量的实际类型
用上面的例子讲解,
1、当解析到类型变量L时,第一次调用scanSuperTypes方法
变量名 | 实际值 |
---|---|
typeVar | L |
srcType | Level2Mapper |
declaringClass | Level0Mapper |
superclass | Level1Mapper<java.util.Date, java.lang.Integer> |
当前srcType并不是参数类型,故无法确定类型变量L的值,需要向上查找
2、第二次调用scanSuperTypes方法
变量名 | 实际值 |
---|---|
typeVar | L |
srcType | Level1Mapper<java.util.Date, java.lang.Integer> |
declaringClass | Level1Mapper |
superclass | Level0Mapper<E, F, java.lang.String> |
当前srcType是参数类型,通过调用translateParentTypeVars方法可以确定类型变量E,F的实际类型为Date和Integer。结合Level0Mapper接口的定义Level0Mapper<L, M, N>可以确定参数类型L的实际类型为Date。
private static Type scanSuperTypes(TypeVariable<?> typeVar, Type srcType, Class<?> declaringClass, Class<?> clazz, Type superclass) {
if (superclass instanceof ParameterizedType) {
ParameterizedType parentAsType = (ParameterizedType) superclass;//父类的参数类型
Class<?> parentAsClass = (Class<?>) parentAsType.getRawType();//声明此类型的类或接口
TypeVariable<?>[] parentTypeVars = parentAsClass.getTypeParameters();//父类类上声明的类型参数
if (srcType instanceof ParameterizedType) {
//将父类声明的参数类型转换成子类定义的实际类型
parentAsType = translateParentTypeVars((ParameterizedType) srcType, clazz, parentAsType);
}
//递归退出条件
if (declaringClass == parentAsClass) {
for (int i = 0; i < parentTypeVars.length; i++) {
if (typeVar.equals(parentTypeVars[i])) {//找到参数类型的实际类型
return parentAsType.getActualTypeArguments()[i];
}
}
}
//声明类型的类是parentAsClass的父类,说明还需要继续递归解析
if (declaringClass.isAssignableFrom(parentAsClass)) {
return resolveTypeVar(typeVar, parentAsType, declaringClass);
}
//当前父类还不是声明方法的类且父类不是参数类型,表示此时还无法确定类型变量的实际类型,说明还需要继续向上递归才能确认类型变量的实际类型
} else if (superclass instanceof Class && declaringClass.isAssignableFrom((Class<?>) superclass)) {
return resolveTypeVar(typeVar, superclass, declaringClass);
}
return null;
}
translateParentTypeVars
主要用于确定类型参数<L,M,N>所对应的实际类型
private static ParameterizedType translateParentTypeVars(ParameterizedType srcType, Class<?> srcClass, ParameterizedType parentType) {
Type[] parentTypeArgs = parentType.getActualTypeArguments();//父类的实际类型参数
Type[] srcTypeArgs = srcType.getActualTypeArguments();//起始类型的实际类型参数
TypeVariable<?>[] srcTypeVars = srcClass.getTypeParameters();//起始类型类上声明的类型参数
Type[] newParentArgs = new Type[parentTypeArgs.length];
boolean noChange = true;
for (int i = 0; i < parentTypeArgs.length; i++) {
if (parentTypeArgs[i] instanceof TypeVariable) {
for (int j = 0; j < srcTypeVars.length; j++) {
if (srcTypeVars[j].equals(parentTypeArgs[i])) {
noChange = false;
newParentArgs[i] = srcTypeArgs[j];
}
}
} else {
newParentArgs[i] = parentTypeArgs[i];
}
}
return noChange ? parentType : new ParameterizedTypeImpl((Class<?>) parentType.getRawType(), null, newParentArgs);
}
resolveTypeVar方法执行逻辑流程图如下:
resolveGenericArrayType
递归解析泛型数组方法
private static Type resolveGenericArrayType(GenericArrayType genericArrayType, Type srcType, Class<?> declaringClass) {
//表示此数组的组件类型的 Type 对象
Type componentType = genericArrayType.getGenericComponentType();
Type resolvedComponentType = null;
if (componentType instanceof TypeVariable) {
resolvedComponentType = resolveTypeVar((TypeVariable<?>) componentType, srcType, declaringClass);
} else if (componentType instanceof GenericArrayType) {
resolvedComponentType = resolveGenericArrayType((GenericArrayType) componentType, srcType, declaringClass);
} else if (componentType instanceof ParameterizedType) {
resolvedComponentType = resolveParameterizedType((ParameterizedType) componentType, srcType, declaringClass);
}
if (resolvedComponentType instanceof Class) {
return Array.newInstance((Class<?>) resolvedComponentType, 0).getClass();
} else {
return new GenericArrayTypeImpl(resolvedComponentType);
}
}
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);
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;
}