java泛型反射&mybatis的TypeParameterResolver

jdk的Type顶级接口

Class类的public Type getGenericSuperclass()

示例

java 复制代码
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;

public class MyList extends ArrayList<String> {
    public static void main(String[] args) {

        Type resultType = MyList.class.getGenericSuperclass();
        if (resultType instanceof ParameterizedType) {
            ParameterizedType paraType = (ParameterizedType) resultType;
            Type[] actualTypeArguments = paraType.getActualTypeArguments();
            System.out.println(String.class.equals(actualTypeArguments[0]));
            System.out.println(ArrayList.class.equals(paraType.getRawType()));
        }

    }
}

好的,我们来详细解释一下 Class 类的 public Type getGenericSuperclass() 方法。

这个方法在 Java 的反射 机制中非常重要,尤其是在处理泛型时。


1. 字面意思

  • getSuperclass():获取(当前类或接口的)直接超类。
  • Generic:泛型的。
  • 所以,getGenericSuperclass() 的意思是:获取带有泛型信息的直接超类

2. 与 getSuperclass() 的区别

为了更好地理解,我们先对比一下它和 getSuperclass() 的区别:

  • Class getSuperclass():

    • 返回一个 Class 对象,表示此 Class 所表示的实体(类、接口、基本类型或 void)的直接超类。
    • 重要 :如果超类是参数化类型 (即带泛型的类),泛型信息会在编译过程中被擦除 。这个方法返回的是原始类型
    • 示例:对于 class MyList extends ArrayList<String>MyList.class.getSuperclass() 返回的是 ArrayList.class(原始类型),我们无法知道它本来是 ArrayList<String>
  • Type getGenericSuperclass():

    • 返回一个 Type 对象,表示此 Class 所表示的实体(类、接口、基本类型或 void)的直接超类。
    • 重要 :如果超类是参数化类型 ,这个方法会保留泛型信息,让我们能够在运行时获取到。
    • 示例:对于 class MyList extends ArrayList<String>MyList.class.getGenericSuperclass() 返回的是一个 ParameterizedType 对象,我们可以从这个对象中提取出 String 这个类型参数。

3. 返回类型 Type

getGenericSuperclass() 返回的是 java.lang.reflect.Type 接口的对象。Type 是 Java 反射中所有类型的顶级接口。它有以下几个重要的实现类/子接口:

  1. Class :表示原始类型或非泛型类。例如,String.class, ArrayList.class
  2. ParameterizedType :表示一个参数化类型,即带泛型参数的类/接口。例如 List<String>, Map<Integer, String>
  3. TypeVariable :表示类型变量。例如泛型类定义中的 T, K, V
  4. GenericArrayType:表示一个元素类型是参数化类型或者类型变量的数组。
  5. WildcardType :表示通配符类型。例如 ?, ? extends Number, ? super Integer

当我们调用 getGenericSuperclass() 时,最常见的返回类型是 Class(当超类不是泛型时)或 ParameterizedType(当超类是泛型时)。


4. 如何使用(核心示例)

假设我们有如下类结构:

java 复制代码
// 一个普通的泛型基类
public class Base<T> {
    private T data;
    // ... getter and setter
}

// 一个子类,继承自Base,并指定了泛型类型为String
public class StringChild extends Base<String> {
}

// 另一个子类,继承自Base,但使用一个类型变量(常用于复杂的泛型设计中)
public class GenericChild<U> extends Base<U> {
}

// 一个非泛型子类
public class RawChild extends Base { // 注意:这里使用了原始类型Base,而不是Base<Something>
}

现在我们来看看如何通过反射获取 StringChild 的父类泛型信息:

java 复制代码
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public class Test {
    public static void main(String[] args) {
        // 获取 StringChild 的泛型超类
        Type genericSuperclass = StringChild.class.getGenericSuperclass();

        // 检查返回的 Type 是否是 ParameterizedType
        if (genericSuperclass instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
            
            // 获取原始类型 (对应于 Base.class)
            Type rawType = parameterizedType.getRawType();
            System.out.println("原始类型: " + rawType); // 输出: class Base
            
            // 获取实际的类型参数 (对应于 <String> 里的 String)
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            if (actualTypeArguments.length > 0) {
                // 因为我们知道 Base 只有一个类型参数 T
                Type firstTypeArgument = actualTypeArguments[0];
                System.out.println("泛型参数类型: " + firstTypeArgument); // 输出: class java.lang.String
            }
        }
    }
}

运行结果:

复制代码
原始类型: class Base
泛型参数类型: class java.lang.String

5. 其他情况的返回值

  • 对于 GenericChild<U>:

    • GenericChild.class.getGenericSuperclass() 返回的也是一个 ParameterizedType
    • 但是 getActualTypeArguments()[0] 返回的是一个 TypeVariable(代表 U),而不是具体的类,因为 U 在编译时尚未确定。
  • 对于 RawChild:

    • RawChild.class.getGenericSuperclass() 返回的是 Base.class(一个 Class 对象,不是 ParameterizedType),因为它的父类声明中使用了原始类型 Base,没有泛型信息。
  • 对于 Object 类本身:

    • Object.class.getGenericSuperclass() 返回 null,因为 Object 没有超类。
  • 对于接口:

    • 此方法用于获取 的超类。接口使用 getGenericInterfaces() 来获取其带泛型信息的父接口。

6. 实际应用场景

这个方法在框架和库的开发中极为常见,特别是那些需要根据运行时类型进行操作的场景:

  1. JSON/GSON 反序列化 :框架需要知道 Base<String> 中的 T 实际上是 String,才能将 JSON 字符串正确地解析成 String 对象,而不是 Object
  2. Spring 框架:在依赖注入、事务管理等场景中,Spring 有时需要获取被代理类的泛型超类信息来做出正确的决策。
  3. DAO/Repository 设计 :创建一个通用的 BaseDao<T>,在子类 UserDao extends BaseDao<User> 中,通过 getGenericSuperclass() 自动获取 User 类,从而无需在 UserDao 中显式声明实体类型。
  4. 类型安全的容器:实现一个能记住其元素类型的容器。

总结

特性 getSuperclass() getGenericSuperclass()
返回类型 Class<? super T> Type
泛型信息 被擦除,只返回原始类型 保留,返回完整的类型信息
主要用途 获取普通的父类信息 在反射中获取父类的泛型参数
核心处理 直接使用 通常需要判断和转换为 ParameterizedType

简单来说,当你需要知道一个类继承的父类具体是什么泛型类型时,就应该使用 getGenericSuperclass()

mybatis的TypeParameterResolverTest

java 复制代码
package org.apache.ibatis.reflection;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import org.apache.ibatis.reflection.typeparam.Calculator;
import org.apache.ibatis.reflection.typeparam.Calculator.SubCalculator;
import org.apache.ibatis.reflection.typeparam.Level0Mapper;
import org.apache.ibatis.reflection.typeparam.Level0Mapper.Level0InnerMapper;
import org.apache.ibatis.reflection.typeparam.Level1Mapper;
import org.apache.ibatis.reflection.typeparam.Level2Mapper;
import org.apache.ibatis.type.TypeReference;
import org.junit.jupiter.api.Test;

class TypeParameterResolverTest {

  @Test
  void returnLv0SimpleClass() throws Exception {
    Class<?> clazz = Level0Mapper.class;

    // Double simpleSelect();
    // 解析返回的是 Double.class
    Method method = clazz.getMethod("simpleSelect");

    Type result = TypeParameterResolver.resolveReturnType(method, clazz);

    assertEquals(Double.class, result);
  }

  @Test
  void returnSimpleVoid() throws Exception {
    Class<?> clazz = Level1Mapper.class;

    // void simpleSelectVoid(Integer param);
    // 解析返回的是 void.class
    Method method = clazz.getMethod("simpleSelectVoid", Integer.class);

    Type result = TypeParameterResolver.resolveReturnType(method, clazz);

    assertEquals(void.class, result);
  }

  @Test
  void returnSimplePrimitive() throws Exception {
    Class<?> clazz = Level1Mapper.class;

    // double simpleSelectPrimitive(int param)
    // 解析返回的是 double.class
    Method method = clazz.getMethod("simpleSelectPrimitive", int.class);
    Type result = TypeParameterResolver.resolveReturnType(method, clazz);
    assertEquals(double.class, result);
  }

  @Test
  void returnSimpleClass() throws Exception {
    Class<?> clazz = Level1Mapper.class;

    // Double simpleSelect()
    // 解析返回的是 Double.class
    Method method = clazz.getMethod("simpleSelect");

    Type result = TypeParameterResolver.resolveReturnType(method, clazz);

    assertEquals(Double.class, result);
  }

  @Test
  void returnSimpleList() throws Exception {
    Class<?> clazz = Level1Mapper.class;

    // List<Double> simpleSelectList();
    // 解析返回的是 ParameterizedType对象,
    // getRawType()是List.class,
    // getActualTypeArguments()[0]是Double.class
    Method method = clazz.getMethod("simpleSelectList");

    Type result = TypeParameterResolver.resolveReturnType(method, clazz);

    assertTrue(result instanceof ParameterizedType);
    ParameterizedType paramType = (ParameterizedType) result;
    assertEquals(List.class, paramType.getRawType());
    assertEquals(1, paramType.getActualTypeArguments().length);
    assertEquals(Double.class, paramType.getActualTypeArguments()[0]);
  }

  @Test
  void returnSimpleMap() throws Exception {
    Class<?> clazz = Level1Mapper.class;

    // Map<Integer, Double> simpleSelectMap();
    // 解析返回的是 ParameterizedType对象,
    // getRawType()Map.class,
    // getActualTypeArguments()[0]是 Integer.class
    // getActualTypeArguments()[1]是 Double.class
    Method method = clazz.getMethod("simpleSelectMap");

    Type result = TypeParameterResolver.resolveReturnType(method, clazz);

    assertTrue(result instanceof ParameterizedType);
    ParameterizedType paramType = (ParameterizedType) result;
    assertEquals(Map.class, paramType.getRawType());
    assertEquals(2, paramType.getActualTypeArguments().length);
    assertEquals(Integer.class, paramType.getActualTypeArguments()[0]);
    assertEquals(Double.class, paramType.getActualTypeArguments()[1]);
    assertEquals("java.util.Map<java.lang.Integer, java.lang.Double>", result.toString());
  }

  @Test
  void returnSimpleWildcard() throws Exception {
    Class<?> clazz = Level1Mapper.class;

    // List<? extends String> simpleSelectWildcard();
    // 解析返回的是 ParameterizedType对象,
    // getRawType()是List.class,
    // getActualTypeArguments()[0]是WildcardType对象, 该对象的getUpperBounds()[0]是String.class
    Method method = clazz.getMethod("simpleSelectWildcard");

    Type result = TypeParameterResolver.resolveReturnType(method, clazz);
    assertTrue(result instanceof ParameterizedType);
    ParameterizedType paramType = (ParameterizedType) result;
    assertEquals(List.class, paramType.getRawType());
    assertEquals(1, paramType.getActualTypeArguments().length);
    assertTrue(paramType.getActualTypeArguments()[0] instanceof WildcardType);
    WildcardType wildcard = (WildcardType) paramType.getActualTypeArguments()[0];
    assertEquals(String.class, wildcard.getUpperBounds()[0]);
    assertEquals("java.util.List<? extends java.lang.String>", paramType.toString());
  }

  @Test
  void returnSimpleArray() throws Exception {

    Class<?> clazz = Level1Mapper.class;

    // String[] simpleSelectArray();
    // 解析返回的是 Class对象, 该对象的isArray()返回true, 该对象的getComponentType()是String.class
    Method method = clazz.getMethod("simpleSelectArray");

    Type result = TypeParameterResolver.resolveReturnType(method, clazz);

    assertTrue(result instanceof Class);
    Class<?> resultClass = (Class<?>) result;
    assertTrue(resultClass.isArray()); // 获取一个Class对象是否是数组类型的Class
    assertEquals(String.class, resultClass.getComponentType()); // 获取数组类型的Class的元素类型
  }

  @Test
  void returnSimpleArrayOfArray() throws Exception {
    Class<?> clazz = Level1Mapper.class;

    // String[][] simpleSelectArrayOfArray()
    // 解析返回的是 Class对象, 该对象的isArray()返回true, 该对象的getComponentType()是String[].class
    Method method = clazz.getMethod("simpleSelectArrayOfArray");

    Type result = TypeParameterResolver.resolveReturnType(method, clazz);

    assertTrue(result instanceof Class);
    Class<?> resultClass = (Class<?>) result;
    assertTrue(resultClass.isArray());
    assertEquals(String[].class, resultClass.getComponentType());
    assertTrue(resultClass.getComponentType().isArray());
    assertEquals(String.class, resultClass.getComponentType().getComponentType());
  }

  @Test
  void returnSimpleTypeVar() throws Exception {
    Class<?> clazz = Level1Mapper.class;

    // <K extends Calculator<?>> K simpleSelectTypeVar()
    // 解析返回的是 ParameterizedType对象,
    // getRawType()是Calculator.class,
    // getActualTypeArguments()[0]是WildcardType对象, 该对象的getUpperBounds()[0]是Object.class
    Method method = clazz.getMethod("simpleSelectTypeVar");

    Type result = TypeParameterResolver.resolveReturnType(method, clazz);

    assertTrue(result instanceof ParameterizedType);
    ParameterizedType paramType = (ParameterizedType) result;
    assertEquals(Calculator.class, paramType.getRawType());
    assertEquals(1, paramType.getActualTypeArguments().length);
    assertTrue(paramType.getActualTypeArguments()[0] instanceof WildcardType);
    assertEquals(Object.class, ((WildcardType) paramType.getActualTypeArguments()[0]).getUpperBounds()[0]);
  }

  @Test
  void returnLv1Class() throws Exception {

    // 注意: Level0Mapper<L, M, N>
    //      Level1Mapper<E, F> extends Level0Mapper<E, F, String>
    //      Level2Mapper extends Level1Mapper<Date, Integer>
    Class<?> clazz = Level1Mapper.class;

    // N select(N param);
    // 解析返回的是 String.class
    Method method = clazz.getMethod("select", Object.class);

    Type result = TypeParameterResolver.resolveReturnType(method, clazz);

    assertEquals(String.class, result);
  }

  @Test
  void returnLv2CustomClass() throws Exception {

    // 注意: Level0Mapper<L, M, N>
    //      Level1Mapper<E, F> extends Level0Mapper<E, F, String>
    //      Level2Mapper extends Level1Mapper<Date, Integer>
    Class<?> clazz = Level2Mapper.class;

    // Calculator<N> selectCalculator(Calculator<N> param);
    // 解析返回的是 ParameterizedType对象,
    // getRawType()是Calculator.class,
    // getActualTypeArguments()[0]是String.class
    Method method = clazz.getMethod("selectCalculator", Calculator.class);

    Type result = TypeParameterResolver.resolveReturnType(method, clazz);

    assertTrue(result instanceof ParameterizedType);
    ParameterizedType paramType = (ParameterizedType) result;
    assertEquals(Calculator.class, paramType.getRawType());
    assertEquals(1, paramType.getActualTypeArguments().length);
    assertEquals(String.class, paramType.getActualTypeArguments()[0]);
  }

  @Test
  void returnLv2CustomClassList() throws Exception {

    // 注意: Level0Mapper<L, M, N>
    //      Level1Mapper<E, F> extends Level0Mapper<E, F, String>
    //      Level2Mapper extends Level1Mapper<Date, Integer>
    Class<?> clazz = Level2Mapper.class;

    // List<Calculator<L>> selectCalculatorList();
    // 解析返回的是 ParameterizedType对象,
    // getRawType()是List.class,
    // getActualTypeArguments()[0]是ParameterizedType对象, 该对象的getRawType()是Calculator.class, 该对象的getActualTypeArguments()[0]是Date.class
    Method method = clazz.getMethod("selectCalculatorList");

    Type result = TypeParameterResolver.resolveReturnType(method, clazz);

    assertTrue(result instanceof ParameterizedType);
    ParameterizedType paramTypeOuter = (ParameterizedType) result;
    assertEquals(List.class, paramTypeOuter.getRawType());
    assertEquals(1, paramTypeOuter.getActualTypeArguments().length);
    ParameterizedType paramTypeInner = (ParameterizedType) paramTypeOuter.getActualTypeArguments()[0];
    assertEquals(Calculator.class, paramTypeInner.getRawType());
    assertEquals(Date.class, paramTypeInner.getActualTypeArguments()[0]);
  }

  @Test
  void returnLv0InnerClass() throws Exception {

    // 注意: Level0Mapper<L, M, N>
    //      Level0InnerMapper extends Level0Mapper<String, Long, Float>
    Class<?> clazz = Level0InnerMapper.class;

    // N select(N param);
    // 解析返回的是 Float.class
    Method method = clazz.getMethod("select", Object.class);

    Type result = TypeParameterResolver.resolveReturnType(method, clazz);

    assertEquals(Float.class, result);
  }

  @Test
  void returnLv2Class() throws Exception {

    // 注意: Level0Mapper<L, M, N>
    //      Level1Mapper<E, F> extends Level0Mapper<E, F, String>
    //      Level2Mapper extends Level1Mapper<Date, Integer>
    Class<?> clazz = Level2Mapper.class;

    // N select(N param);
    // 解析返回的是 String.class
    Method method = clazz.getMethod("select", Object.class);
    // Method method = Level0Mapper.class.getMethod("select", Object.class); // 这样也可以获取

    Type result = TypeParameterResolver.resolveReturnType(method, clazz);

    assertEquals(String.class, result);
  }

  @Test
  void returnLv1List() throws Exception {

    // 注意: Level0Mapper<L, M, N>
    //      Level1Mapper<E, F> extends Level0Mapper<E, F, String>
    Class<?> clazz = Level1Mapper.class;

    // List<N> selectList(M param1, N param2);
    // 解析返回的是 ParameterizedType对象,
    Method method = clazz.getMethod("selectList", Object.class, Object.class);

    Type result = TypeParameterResolver.resolveReturnType(method, clazz);

    assertTrue(result instanceof ParameterizedType);
    ParameterizedType type = (ParameterizedType) result;
    assertEquals(List.class, type.getRawType());
    assertEquals(1, type.getActualTypeArguments().length);
    assertEquals(String.class, type.getActualTypeArguments()[0]);
  }

  @Test
  void returnLv1Array() throws Exception {

    // 注意: Level0Mapper<L, M, N>
    //      Level1Mapper<E, F> extends Level0Mapper<E, F, String>
    Class<?> clazz = Level1Mapper.class;

    // N[] selectArray(List<N>[] param);
    // 解析返回的是 String[].class
    Method method = clazz.getMethod("selectArray", List[].class);

    Type result = TypeParameterResolver.resolveReturnType(method, clazz);

    assertTrue(result instanceof Class);
    Class<?> resultClass = (Class<?>) result;
    assertTrue(resultClass.isArray());
    assertEquals(String.class, resultClass.getComponentType());
  }

  @Test
  void returnLv2ArrayOfArray() throws Exception {

    // 注意: Level0Mapper<L, M, N>
    //      Level1Mapper<E, F> extends Level0Mapper<E, F, String>
    //      Level2Mapper extends Level1Mapper<Date, Integer>
    Class<?> clazz = Level2Mapper.class;

    // N[][] selectArrayOfArray();
    // 解析返回的是 String[][].class
    Method method = clazz.getMethod("selectArrayOfArray");

    Type result = TypeParameterResolver.resolveReturnType(method, clazz);

    assertTrue(result instanceof Class);
    Class<?> resultClass = (Class<?>) result;
    assertTrue(resultClass.isArray());
    assertTrue(resultClass.getComponentType().isArray());
    assertEquals(String.class, resultClass.getComponentType().getComponentType());
  }

  @Test
  void returnLv2ArrayOfList() throws Exception {

    // 注意: Level0Mapper<L, M, N>
    //      Level1Mapper<E, F> extends Level0Mapper<E, F, String>
    //      Level2Mapper extends Level1Mapper<Date, Integer>
    Class<?> clazz = Level2Mapper.class;

    // List<N>[] selectArrayOfList();
    // 解析返回的是 GenericArrayType 对象,
    // getGenericComponentType()是ParameterizedType对象, 该对象的getRawType()是List.class, 该对象的getActualTypeArguments()[0]是String.class
    Method method = clazz.getMethod("selectArrayOfList");

    Type result = TypeParameterResolver.resolveReturnType(method, clazz);

    assertTrue(result instanceof GenericArrayType);
    GenericArrayType genericArrayType = (GenericArrayType) result;
    assertTrue(genericArrayType.getGenericComponentType() instanceof ParameterizedType);
    ParameterizedType paramType = (ParameterizedType) genericArrayType.getGenericComponentType();
    assertEquals(List.class, paramType.getRawType());
    assertEquals(String.class, paramType.getActualTypeArguments()[0]);
  }

  @Test
  void returnLv2WildcardList() throws Exception {

    // 注意: Level0Mapper<L, M, N>
    //      Level1Mapper<E, F> extends Level0Mapper<E, F, String>
    //      Level2Mapper extends Level1Mapper<Date, Integer>
    Class<?> clazz = Level2Mapper.class;

    // List<? extends N> selectWildcardList();
    // 解析返回的是 ParameterizedType对象,
    // 该对象的getRawType()是List.class,
    // 该对象getActualTypeArguments()[0]是WildcardType对象, 该WildcardType对象getUpperBounds()[0]是String.class
    Method method = clazz.getMethod("selectWildcardList");
    // Method method = Level0Mapper.class.getMethod("selectWildcardList"); // 这样也可以

    Type result = TypeParameterResolver.resolveReturnType(method, clazz);

    assertTrue(result instanceof ParameterizedType);
    ParameterizedType type = (ParameterizedType) result;
    assertEquals(List.class, type.getRawType());
    assertEquals(1, type.getActualTypeArguments().length);
    assertTrue(type.getActualTypeArguments()[0] instanceof WildcardType);
    WildcardType wildcard = (WildcardType) type.getActualTypeArguments()[0];
    assertEquals(0, wildcard.getLowerBounds().length);
    assertEquals(1, wildcard.getUpperBounds().length);
    assertEquals(String.class, wildcard.getUpperBounds()[0]);
  }

  @Test
  void returnLV1Map() throws Exception {

    // 注意: Level0Mapper<L, M, N>
    //      Level1Mapper<E, F> extends Level0Mapper<E, F, String>
    Class<?> clazz = Level1Mapper.class;

    // Map<N, M> selectMap();
    // 解析返回的是 ParameterizedType对象,
    // 该对象的getRawType()是Map.class,
    // 该对象getActualTypeArguments()[0]是String.class,
    // 该对象getActualTypeArguments()[1]是Object.class(这个泛型M由于未指定具体类型, 所以是Object.class)
    Method method = clazz.getMethod("selectMap");

    Type result = TypeParameterResolver.resolveReturnType(method, clazz);

    assertTrue(result instanceof ParameterizedType);
    ParameterizedType paramType = (ParameterizedType) result;
    assertEquals(Map.class, paramType.getRawType());
    assertEquals(2, paramType.getActualTypeArguments().length);
    assertEquals(String.class, paramType.getActualTypeArguments()[0]);
    assertEquals(Object.class, paramType.getActualTypeArguments()[1]);
  }

  @Test
  void returnLV2Map() throws Exception {

    // 注意: Level0Mapper<L, M, N>
    //      Level1Mapper<E, F> extends Level0Mapper<E, F, String>
    //      Level2Mapper extends Level1Mapper<Date, Integer>
    Class<?> clazz = Level2Mapper.class;

    // Map<N, M> selectMap();
    // 解析返回的是 ParameterizedType对象,
    // 该对象的getRawType()是Map.class,
    // 该对象getActualTypeArguments()[0]是String.class,
    // 该对象getActualTypeArguments()[1]是Integer.class
    Method method = clazz.getMethod("selectMap");

    Type result = TypeParameterResolver.resolveReturnType(method, clazz);

    assertTrue(result instanceof ParameterizedType);
    ParameterizedType paramType = (ParameterizedType) result;
    assertEquals(Map.class, paramType.getRawType());
    assertEquals(2, paramType.getActualTypeArguments().length);
    assertEquals(String.class, paramType.getActualTypeArguments()[0]);
    assertEquals(Integer.class, paramType.getActualTypeArguments()[1]);
  }

  @Test
  void returnSubclass() throws Exception {
    // 注意: Calculator<T>
    //      SubCalculator extends Calculator<String>
    Class<?> clazz = SubCalculator.class;

    // T getId();
    // 解析返回的是 String.class
    Method method = clazz.getMethod("getId");

    Type result = TypeParameterResolver.resolveReturnType(method, clazz);

    assertEquals(String.class, result);
  }

  @Test
  void paramPrimitive() throws Exception {
    // 注意: Level0Mapper<L, M, N>
    //      Level1Mapper<E, F> extends Level0Mapper<E, F, String>
    //      Level2Mapper extends Level1Mapper<Date, Integer>
    Class<?> clazz = Level2Mapper.class;

    // double simpleSelectPrimitive(int param);
    // 解析方法参数返回的是 [int.class]
    Method method = clazz.getMethod("simpleSelectPrimitive", int.class);

    Type[] result = TypeParameterResolver.resolveParamTypes(method, clazz);

    assertEquals(1, result.length);
    assertEquals(int.class, result[0]);
  }

  @Test
  void paramSimple() throws Exception {

    // 注意: Level0Mapper<L, M, N>
    //      Level1Mapper<E, F> extends Level0Mapper<E, F, String>
    Class<?> clazz = Level1Mapper.class;

    // void simpleSelectVoid(Integer param);
    // 解析方法参数返回的是 [Integer.class]
    Method method = clazz.getMethod("simpleSelectVoid", Integer.class);

    Type[] result = TypeParameterResolver.resolveParamTypes(method, clazz);

    assertEquals(1, result.length);
    assertEquals(Integer.class, result[0]);
  }

  @Test
  void paramLv1Single() throws Exception {
    // 注意: Level0Mapper<L, M, N>
    //      Level1Mapper<E, F> extends Level0Mapper<E, F, String>
    Class<?> clazz = Level1Mapper.class;

    // N select(N param);
    // 解析方法参数返回的是 [String.class]
    Method method = clazz.getMethod("select", Object.class);
    // Method method = clazz.getMethod("select", String.class); // 注意这里是获取不到这个select带泛型的方法的!!!

    Type[] result = TypeParameterResolver.resolveParamTypes(method, clazz);

    assertEquals(1, result.length);
    assertEquals(String.class, result[0]);
  }

  @Test
  void paramLv2Single() throws Exception {

    // 注意: Level0Mapper<L, M, N>
    //      Level1Mapper<E, F> extends Level0Mapper<E, F, String>
    //      Level2Mapper extends Level1Mapper<Date, Integer>
    Class<?> clazz = Level2Mapper.class;

    // N select(N param);
    // 解析方法参数返回的是 [String.class]
    Method method = clazz.getMethod("select", Object.class);
    // Method method = clazz.getMethod("select", String.class); // 注意这里是获取不到这个select带泛型的方法的!!!

    Type[] result = TypeParameterResolver.resolveParamTypes(method, clazz);

    assertEquals(1, result.length);
    assertEquals(String.class, result[0]);
  }

  @Test
  void paramLv2Multiple() throws Exception {

    // 注意: Level0Mapper<L, M, N>
    //      Level1Mapper<E, F> extends Level0Mapper<E, F, String>
    //      Level2Mapper extends Level1Mapper<Date, Integer>
    Class<?> clazz = Level2Mapper.class;

    // N selectList(M param1, N param2);
    // 解析方法参数返回的是 [Integer.class, String.class]
    Method method = clazz.getMethod("selectList", Object.class, Object.class);
    // Method method = clazz.getMethod("selectList", Date.class, Integer.class); // 注意这里是获取不到这个selectList带泛型的方法的!!!

    Type[] result = TypeParameterResolver.resolveParamTypes(method, clazz);

    assertEquals(2, result.length);
    assertEquals(Integer.class, result[0]);
    assertEquals(String.class, result[1]);
  }

  @Test
  void paramLv2CustomClass() throws Exception {
    // 注意: Level0Mapper<L, M, N>
    //      Level1Mapper<E, F> extends Level0Mapper<E, F, String>
    //      Level2Mapper extends Level1Mapper<Date, Integer>
    Class<?> clazz = Level2Mapper.class;

    // Calculator<N> selectCalculator(Calculator<N> param);
    // 解析方法参数返回的是 [ParameterizedType对象],
    // 该对象的getRawType()方法返回的是 Calculator.class,
    // 该对象的getActualTypeArguments()[0]方法返回的是 String.class
    Method method = clazz.getMethod("selectCalculator", Calculator.class);

    Type[] result = TypeParameterResolver.resolveParamTypes(method, clazz);

    assertEquals(1, result.length);
    assertTrue(result[0] instanceof ParameterizedType);
    ParameterizedType paramType = (ParameterizedType) result[0];
    assertEquals(Calculator.class, paramType.getRawType());
    assertEquals(1, paramType.getActualTypeArguments().length);
    assertEquals(String.class, paramType.getActualTypeArguments()[0]);
  }

  @Test
  void paramLv1Array() throws Exception {
    // 注意: Level0Mapper<L, M, N>
    //      Level1Mapper<E, F> extends Level0Mapper<E, F, String>
    Class<?> clazz = Level1Mapper.class;

    // N[] selectArray(List<N>[] param);
    // 解析方法参数返回的是 [GenericArrayType 对象],
    // 该对象的 getGenericComponentType() 方法返回的是 ParameterizedType对象,
    // 该 ParameterizedType对象 的getActualTypeArguments() 方法返回的是 String.class
    Method method = clazz.getMethod("selectArray", List[].class);

    Type[] result = TypeParameterResolver.resolveParamTypes(method, clazz);

    assertTrue(result[0] instanceof GenericArrayType);
    GenericArrayType genericArrayType = (GenericArrayType) result[0];
    assertTrue(genericArrayType.getGenericComponentType() instanceof ParameterizedType);
    assertEquals("java.util.List<java.lang.String>[]", genericArrayType.toString());
    ParameterizedType paramType = (ParameterizedType) genericArrayType.getGenericComponentType();
    assertEquals(List.class, paramType.getRawType());
    assertEquals(String.class, paramType.getActualTypeArguments()[0]);
  }

  @Test
  void paramSubclass() throws Exception {
    // 注意: Calculator<T>
    //      SubCalculator extends Calculator<String>
    Class<?> clazz = SubCalculator.class;

    // 解析方法参数返回的是 [String.class],
    Method method = clazz.getMethod("setId", Object.class);
    // Method method = clazz.getMethod("setId", String.class); // 注意这里是获取不到这个selectList带泛型的方法的!!!

    Type[] result = TypeParameterResolver.resolveParamTypes(method, clazz);
    assertEquals(String.class, result[0]);
  }

  @Test
  void paramGeneric() throws Exception {

    // 使用TypeReference保存泛型信息, 然后使用TypeParameterResolver获取泛型信息
    // 这使得在没有具体的子类实现的情况下, 也可以使用TypeReference得到泛型信息
    /*
    可对比如下示例, 方便类比理解
    public class MyList extends ArrayList<String> {
        public static void main(String[] args) {

            Type resultType = MyList.class.getGenericSuperclass();
            if (resultType instanceof ParameterizedType) {
                ParameterizedType paraType = (ParameterizedType) resultType;
                Type[] actualTypeArguments = paraType.getActualTypeArguments();
                System.out.println(String.class.equals(actualTypeArguments[0]));
                System.out.println(ArrayList.class.equals(paraType.getRawType()));
            }

        }
    }
    */
    TypeReference<ParentIface<String>> type = new TypeReference<ParentIface<String>>() { };

    // List<T> m();
    // 解析方法参数返回的是 [ParameterizedType对象],
    // 该ParameterizedType对象 的getActualTypeArguments() 返回的是 String.class
    Method method = ParentIface.class.getMethod("m");

    // 注意这里与前面的区别: 这里的第一个参数是方法对象, 第二个参数是 ParameterizedType对象!!!
    // 第二个参数 等价于 ParentIface<String>的泛型信息
    Type result = TypeParameterResolver.resolveReturnType(method, type.getRawType());

    assertTrue(result instanceof ParameterizedType);
    ParameterizedType parameterizedType = (ParameterizedType) result;
    assertEquals(List.class, parameterizedType.getRawType());
    Type[] typeArgs = parameterizedType.getActualTypeArguments();
    assertEquals(1, typeArgs.length);
    assertEquals(String.class, typeArgs[0]);
  }

  @Test
  void returnAnonymous() throws Exception {

    // 注意: Calculator<T>
    Calculator<?> instance = new Calculator<Integer>();
    Class<?> clazz = instance.getClass();
    Method method = clazz.getMethod("getId");

    // 解析返回的是 Object.class
    Type result = TypeParameterResolver.resolveReturnType(method, clazz);

    assertEquals(Object.class, result);
  }

  @Test
  void fieldGenericField() throws Exception {

    // 注意: Calculator<T>
    //      SubCalculator extends Calculator<String>
    Class<?> clazz = SubCalculator.class;

    Class<?> declaredClass = Calculator.class;

    Field field = declaredClass.getDeclaredField("fld");

    // 解析返回的是 String.class
    Type result = TypeParameterResolver.resolveFieldType(field, clazz);

    assertEquals(String.class, result);
  }

  @Test
  void returnParamWildcardWithUpperBounds() throws Exception {
    class Key {
    }
    @SuppressWarnings("unused")
    class KeyBean<S extends Key & Cloneable, T extends Key> {
      private S key1;
      private T key2;

      public S getKey1() {
        return key1;
      }

      public void setKey1(S key1) {
        this.key1 = key1;
      }

      public T getKey2() {
        return key2;
      }

      public void setKey2(T key2) {
        this.key2 = key2;
      }
    }

    Class<?> clazz = KeyBean.class;
    Method getter1 = clazz.getMethod("getKey1");
    assertEquals(Key.class, TypeParameterResolver.resolveReturnType(getter1, clazz));

    Method setter1 = clazz.getMethod("setKey1", Key.class);
    assertEquals(Key.class, TypeParameterResolver.resolveParamTypes(setter1, clazz)[0]);

    Method getter2 = clazz.getMethod("getKey2");
    assertEquals(Key.class, TypeParameterResolver.resolveReturnType(getter2, clazz));

    Method setter2 = clazz.getMethod("setKey2", Key.class);
    assertEquals(Key.class, TypeParameterResolver.resolveParamTypes(setter2, clazz)[0]);
  }

  @Test
  void deepHierarchy() throws Exception {
    @SuppressWarnings("unused")
    abstract class A<S> {
      protected S id;

      public S getId() {
        return this.id;
      }

      public void setId(S id) {
        this.id = id;
      }
    }
    abstract class B<T> extends A<T> {
    }
    abstract class C<U> extends B<U> {
    }
    class D extends C<Integer> {
    }

    Class<?> clazz = D.class;
    Method method = clazz.getMethod("getId");
    assertEquals(Integer.class, TypeParameterResolver.resolveReturnType(method, clazz));

    Field field = A.class.getDeclaredField("id");
    assertEquals(Integer.class, TypeParameterResolver.resolveFieldType(field,  D.class));
    assertEquals(Object.class, TypeParameterResolver.resolveFieldType(field, A.class));
  }

  @Test
  void shouldTypeVariablesBeComparedWithEquals() throws Exception {
    // #1794
    ExecutorService executor = Executors.newFixedThreadPool(2);
    Future<Type> futureA = executor.submit(() -> {
      Type retType = TypeParameterResolver.resolveReturnType(IfaceA.class.getMethods()[0], IfaceA.class);
      return ((ParameterizedType) retType).getActualTypeArguments()[0];
    });
    Future<Type> futureB = executor.submit(() -> {
      Type retType = TypeParameterResolver.resolveReturnType(IfaceB.class.getMethods()[0], IfaceB.class);
      return ((ParameterizedType) retType).getActualTypeArguments()[0];
    });
    assertEquals(AA.class, futureA.get());
    assertEquals(BB.class, futureB.get());
    executor.shutdown();
  }

  @Test
  void shouldResolveInterfaceTypeParams() {
    // 解析父子类继承关系中,父类中 类 类型参数
    Type[] types = TypeParameterResolver.resolveClassTypeParams(ParentIface.class, IntegerHandler.class);
    assertEquals(1, types.length);
    assertEquals(Integer.class, types[0]);
  }

  @Test
  void shouldResolveInterfaceTypeParamsDeep() {
    // 解析父子类继承关系中(多层级的情况),父类中 类 类型参数
    Type[] types = TypeParameterResolver.resolveClassTypeParams(ParentIface.class, StringHandler.class);
    assertEquals(1, types.length);
    assertEquals(String.class, types[0]);
  }

  @Test
  void shouldResolveInterfaceTypeParamsDeeper() {
    // 解析父子类继承关系中(多层级的情况 + 复杂情况),父类中 类 类型参数
    Type[] types = TypeParameterResolver.resolveClassTypeParams(ParentIface.class, CustomStringHandler3.class);
    assertEquals(1, types.length);
    assertEquals(String.class, types[0]);
  }

  class AA {
  }

  class BB {
  }

  interface IfaceA extends ParentIface<AA> {
  }

  interface IfaceB extends ParentIface<BB> {
  }

  interface ParentIface<T> {
    List<T> m();
  }

  abstract class BaseHandler<T> implements ParentIface<T> {
  }

  class StringHandler extends BaseHandler<String> {
    public List<String> m() {
      return null;
    }
  }

  class CustomStringHandler extends StringHandler {
  }

  class CustomStringHandler2<T> extends CustomStringHandler {
  }

  class CustomStringHandler3 extends CustomStringHandler2<Integer> {
  }

  class IntegerHandler implements Cloneable, ParentIface<Integer> {
    public List<Integer> m() {
      return null;
    }
  }

  @Test
  void shouldParameterizedTypesWithOwnerTypeBeEqual() throws Exception {
    class Clazz {
      @SuppressWarnings("unused")
      public Entry<String, Integer> entry() {
        return null;
      }
    }

    Type typeJdk = Clazz.class.getMethod("entry").getGenericReturnType();

    Class<?> clazz = Level2Mapper.class;
    Method method = clazz.getMethod("selectEntry");
    Type typeMybatis = TypeParameterResolver.resolveReturnType(method, clazz);

    // 这里在告诉我们mybatis实现的ParameterizedTypeImpl就可类比jdk的ParameterizedTypeImpl
    assertTrue(typeJdk instanceof ParameterizedType && !(typeJdk instanceof TypeParameterResolver.ParameterizedTypeImpl));
    assertTrue(typeMybatis instanceof TypeParameterResolver.ParameterizedTypeImpl);
    assertTrue(typeJdk.equals(typeMybatis));
    assertTrue(typeMybatis.equals(typeJdk));
  }

  @Test
  void shouldWildcardTypeBeEqual() throws Exception {
    class WildcardTypeTester {
      @SuppressWarnings("unused")
      public List<? extends Serializable> foo() {
        return null;
      }
    }

    Class<?> clazz = WildcardTypeTester.class;
    Method foo = clazz.getMethod("foo");

    // mybatis的方法的返回类型
    Type typeMybatis = TypeParameterResolver.resolveReturnType(foo, clazz);
    // jdk的方法的返回类型
    Type typeJdk = foo.getGenericReturnType();

    Type wildcardMybatis = ((ParameterizedType) typeMybatis).getActualTypeArguments()[0];
    Type wildcardJdk = ((ParameterizedType) typeJdk).getActualTypeArguments()[0];

    // 这里在告诉我们mybatis实现的WildcardTypeImpl也可类比jdk的WildcardTypeImpl
    assertTrue(wildcardJdk instanceof WildcardType && !(wildcardJdk instanceof TypeParameterResolver.WildcardTypeImpl));
    assertTrue(wildcardMybatis instanceof TypeParameterResolver.WildcardTypeImpl);
    assertTrue(typeJdk.equals(typeMybatis));
    assertTrue(typeMybatis.equals(typeJdk));
  }

  @Test
  void shouldGenericArrayTypeBeEqual() throws Exception {
    class GenericArrayTypeTester {
      @SuppressWarnings("unused")
      public List<String>[] foo() {
        return null;
      }
    }

    Class<?> clazz = GenericArrayTypeTester.class;
    Method foo = clazz.getMethod("foo");
    Type typeMybatis = TypeParameterResolver.resolveReturnType(foo, clazz);
    Type typeJdk = foo.getGenericReturnType();

    // 这里在告诉我们mybatis实现的GenericArrayTypeImpl也可类比jdk的GenericArrayTypeImpl
    assertTrue(typeJdk instanceof GenericArrayType && !(typeJdk instanceof TypeParameterResolver.GenericArrayTypeImpl));
    assertTrue(typeMybatis instanceof TypeParameterResolver.GenericArrayTypeImpl);
    assertTrue(typeJdk.equals(typeMybatis));
    assertTrue(typeMybatis.equals(typeJdk));
  }

  @Test
  void shouldNestedParamTypeToStringOmitCommonFqn() throws Exception {
    Class<?> clazz = Level2Mapper.class;
    Method method = clazz.getMethod("selectMapEntry");
    Type type = TypeParameterResolver.resolveReturnType(method, clazz);
    assertEquals("java.util.Map<java.util.Map$Entry<java.lang.String, java.lang.Integer>, java.util.Date>", type.toString());
  }

  static class Outer<T> {

    class Inner {
    }

    public Inner foo() {
      return null;
    }

  }

  static class InnerTester {

    public Outer<?>.Inner noTypeOuter() {
      return null;
    }

    public Outer<String>.Inner stringTypeOuter() {
      return null;
    }

  }

  @Test
  void shouldToStringHandleInnerClass() throws Exception {
    Class<?> outerClass = Outer.class;
    Class<?> innerTesterClass = InnerTester.class;
    Method foo = outerClass.getMethod("foo");
    Method noTypeOuter = innerTesterClass.getMethod("noTypeOuter");
    Method stringTypeOuter = innerTesterClass.getMethod("stringTypeOuter");

    Type fooReturnType = TypeParameterResolver.resolveReturnType(foo, outerClass);
    Type noTypeOuterReturnType = TypeParameterResolver.resolveReturnType(noTypeOuter, innerTesterClass);
    Type stringTypeOuterReturnType = TypeParameterResolver.resolveReturnType(stringTypeOuter, innerTesterClass);

    assertEquals("org.apache.ibatis.reflection.TypeParameterResolverTest$Outer<T>$Inner", fooReturnType.toString());
    assertEquals("org.apache.ibatis.reflection.TypeParameterResolverTest$Outer<?>$Inner", noTypeOuterReturnType.toString());
    assertEquals("org.apache.ibatis.reflection.TypeParameterResolverTest$Outer<java.lang.String>$Inner", stringTypeOuterReturnType.toString());
  }

}
相关推荐
0***v7771 小时前
springboot 异步操作
java·spring boot·mybatis
LSL666_1 小时前
7 SpringBoot pom.xml解释
java·spring boot·spring
b***59431 小时前
springboot+mybaties项目中扫描不到@mapper注解的解决方法
java·spring boot·mybatis
u***42071 小时前
Spring Boot 实战篇(四):实现用户登录与注册功能
java·spring boot·后端
慕沐.1 小时前
【算法】冒泡排序的原理及实现
java·算法·排序算法
v***8571 小时前
Java进阶-在Ubuntu上部署SpringBoot应用
java·spring boot·ubuntu
kyle~1 小时前
C++ --- noexcept关键字 明确函数不抛出任何异常
java·开发语言·c++
__万波__1 小时前
二十三种设计模式(四)--原型模式
java·设计模式·原型模式
沐浴露z1 小时前
详解Java ArrayList
java·开发语言·哈希算法