mybatis源码学习------TypeParameterResolver

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方法

变量名实际值
typeVarL
srcTypeLevel2Mapper
declaringClassLevel0Mapper
superclassLevel1Mapper<java.util.Date, java.lang.Integer>

当前srcType并不是参数类型,故无法确定类型变量L的值,需要向上查找

2、第二次调用scanSuperTypes方法

变量名实际值
typeVarL
srcTypeLevel1Mapper<java.util.Date, java.lang.Integer>
declaringClassLevel1Mapper
superclassLevel0Mapper<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;
}
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值