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 反射中所有类型的顶级接口。它有以下几个重要的实现类/子接口:
Class:表示原始类型或非泛型类。例如,String.class,ArrayList.class。ParameterizedType:表示一个参数化类型,即带泛型参数的类/接口。例如List<String>,Map<Integer, String>。TypeVariable:表示类型变量。例如泛型类定义中的T,K,V。GenericArrayType:表示一个元素类型是参数化类型或者类型变量的数组。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. 实际应用场景
这个方法在框架和库的开发中极为常见,特别是那些需要根据运行时类型进行操作的场景:
- JSON/GSON 反序列化 :框架需要知道
Base<String>中的T实际上是String,才能将 JSON 字符串正确地解析成String对象,而不是Object。 - Spring 框架:在依赖注入、事务管理等场景中,Spring 有时需要获取被代理类的泛型超类信息来做出正确的决策。
- DAO/Repository 设计 :创建一个通用的
BaseDao<T>,在子类UserDao extends BaseDao<User>中,通过getGenericSuperclass()自动获取User类,从而无需在UserDao中显式声明实体类型。 - 类型安全的容器:实现一个能记住其元素类型的容器。
总结
| 特性 | 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());
}
}