TypeTools
一个非常厉害的库,可以解析大部分的泛型信息了,包括很难取到的lambda表达式匿名内部类的泛型结果
官方文档👉Github - TypeTools
<dependency>
<groupId>net.jodah</groupId>
<artifactId>typetools</artifactId>
<version>0.6.3</version>
</dependency>
非常轻量,整个依赖只有两个java文件
获取一般泛型的方法
一般来说,类、字段、方法参数上的具体泛型可以通过简单的反射获取,想获取一个类其实现接口的泛型class Foo implements Bar<String>,或者某个字段List<String>的 泛型String, ,获取实现的接口泛型信息用.getGenericInterfaces()、继承用.getGenericSuperclass(),然后将其中元素转换为ParameterizedType再使用.getActualTypeArguments() 就可以获取泛型参数了
@Test
void getActualTypeArguments() {
Type[] actualTypeArguments = ((ParameterizedType) Foo.class.getGenericInterfaces()[0]).getActualTypeArguments();
System.out.println(Arrays.toString(actualTypeArguments));
Bar<String> bar = new Bar<String>() {
@Override
public void run(String s) {
}
};
actualTypeArguments = ((ParameterizedType) bar.getClass().getGenericInterfaces()[0]).getActualTypeArguments();
System.out.println(Arrays.toString(actualTypeArguments));
}
interface Bar<T>{void run(T t);}
static class Foo implements Bar<String> {
@Override
public void run(String s) {
}
}
这个方法直到匿名内部类都是可以用的,但是对于强迫症患者点了一下idea提示,把匿名内部类变成lambda的时候,就无法使用此方法获取泛型参数了,因为lambda会把泛型变为<?> ,但是这个工具厉害的地方就是对于lambda依然能够获取
TypeTools 获取泛型
Function<String, Integer> strToInt = Integer::valueOf;
Class<?>[] typeArgs = TypeResolver.resolveRawArguments(Function.class, strToInt.getClass());
System.out.println(Arrays.toString(typeArgs));
lambda 甚至是方法引用,都可以获取到泛型参数
Type reify(Type type, Class<S> context)使用来自context的类型变量信息返回一个完全具体化的type.Type reify(Type genericType)使用泛型声明中的信息返回完全具体化的genericType.Class<?>[] resolveRawArguments(Class<T> type, Class<S> subType)使用来自subType的类型变量信息解析type的原始参数.Class<?> resolveRawArgument(Class<T> type, Class<S> subType)使用来自subType的类型变量信息解析type的原始参数.Type resolveGenericType(Class<?> type, Type subType)使用来自subType的类型变量信息解析泛型type.Class<?> resolveRawClass(Type genericType, Class<?> subType)使用来自subType的类型变量信息解析genericType的原始类.
interface Foo<T> {}
class Bar implements Foo<List<Integer>> {}
Type typeArgs = TypeResolver.reify(Foo.class, Bar.class);
ParameterizedType paramType = (ParameterizedType) typeArgs;
Type[] actualTypeArgs = paramType.getActualTypeArguments();
ParameterizedType arg = (ParameterizedType)actualTypeArgs[0];
assert paramType.getRawType() == Foo.class;
assert arg1.getRawType() == List.class;
assert arg1.getActualTypeArguments()[0] == Integer.class;
不过由于java本身的限制或者太过困难,尽管这个工具很强大了,但也不是所有泛型都能获取的
- 如果接口只定义泛型,但是放着完全不用,那就是取不到的
public interface Foo<A,B,C,D>{
void run(A a);
}
@Test
void test_2021_12_04_22_22_33() {
Foo<String,Integer,Boolean,Character> foo = a->{};
System.out.println(Arrays.toString(TypeResolver.resolveRawArguments(Foo.class, foo.getClass())));
}
输出:
[class java.lang.String,
class net.jodah.typetools.TypeResolver$Unknown,
class net.jodah.typetools.TypeResolver$Unknown,
class net.jodah.typetools.TypeResolver$Unknown]
- 或者用到泛型的地方又套了一个泛型对象 issures 58
public interface Foo<A,B>{
List<B> run(A a);
}
@Test
void test_2021_12_04_22_22_33() {
Foo<String,Integer> foo = a->new ArrayList<>();
System.out.println(Arrays.toString(TypeResolver.resolveRawArguments(Foo.class, foo.getClass())));
}
[class java.lang.String,
class net.jodah.typetools.TypeResolver$Unknown]