随着泛型用的越来越多,获取泛型实际类型信息的需求也会出现,如果用原生API,需要很多步操作才能获取到泛型
以下API为本文讲解 ResolvableType 依赖的API,我们先来简单看下:
public class GenericInjectTest {
public interface Service<N, M> {
}
@org.springframework.stereotype.Service
public class ABService implements Service<A, B> {
}
@org.springframework.stereotype.Service
public class CDService implements Service<C, D> {
}
}
ABService和CDService为Service接口的实现类,我们视A/B/C/D为具体的泛型类型,如果我们获取ABService的第一个泛型类型B,我们用原生API怎么写呢?
// 获取ABService类实现的泛型接口Array的第一个接口Type,这里为Service接口
ParameterizedType parameterizedType = (ParameterizedType)ABService.class.getGenericInterfaces()[0];
// 获取实现的Service接口的第二个泛型Type
Type classBType= parameterizedType.getActualTypeArguments()[1];
Spring提供的ResolvableType API,提供了更加简单易用的泛型操作支持,使用ResolvableType我们如何实现上述问题呢?
ResolvableType resolvableType1 = ResolvableType.forClass(ABService.class);
Class<?> classB = resolvableType1.as(Service.class).getGeneric(1).resolve();
下面我们来具体看下Spring提供的ResolvableType API中的一些具体的用法:
1、获取类级别泛型
ResolvableType resolvableType1 = ResolvableType.forClass(ABService.class);
// 泛型信息放在 Service<A, B> 上,所以需要resolvableType1.getInterfaces()[0]得到
// 得到泛型参数的第1个位置(从0开始)的类型信息
// 通过getGeneric(泛型参数索引)得到某个位置的泛型,resolve()把实际泛型参数解析出来
Class<?> classB = resolvableType1.getInterfaces()[0].getGeneric(1).resolve()
2.、获取字段级别泛型
假设我们的字段如下:
private Service<A, B> abService;
private Service<C, D> cdService;
private List<List<String>> list;
private Map<String, Map<String, Integer>> map;
private List<String>[] array;
如何获取字段 cdService 的第二个泛型参数?
ResolvableType resolvableType2 =
ResolvableType.forField(ReflectionUtils.findField(GenricInjectTest.class, "cdService"));
// 然后通过如下API得到Service<C, D>的第1个位置上的泛型实参类型,即D
resolvableType2.getGeneric(0).resolve()
字段List<List<String>> list,是一种嵌套的泛型参数,那我们如何获取泛型List<String>中的泛型String类型呢?
// 1
ResolvableType resolvableType3 =
ResolvableType.forField(ReflectionUtils.findField(GenricInjectTest.class, "list"));
// 2
resolvableType3.getGeneric(0).getGeneric(0).resolve();
// 第二步更简单的写法是
resolvableType3.getGeneric(0, 0).resolve(); //List<List<String>> 即String
比如Map<String, Map<String, Integer>> map;我们想得到泛型Integer类型,可以使用:
ResolvableType resolvableType4 =
ResolvableType.forField(ReflectionUtils.findField(GenricInjectTest.class, "map"));
resolvableType4.getGeneric(1).getGeneric(1).resolve();
// 更简单的写法
resolvableType4.getGeneric(1, 1).resolve();
// 甚至还能继续优化写法 getGeneric(1, 1).resolve() 可继续优化为 resolveGeneric(1,1)
3、获取方法返回值级别泛型
假设我们的方法如下:
private HashMap<String, List<String>> method() {
return null;
}
得到Map中的List中的String泛型实参:
ResolvableType resolvableType5 =
ResolvableType.forMethodReturnType(ReflectionUtils.findMethod(GenricInjectTest.class, "method"));
resolvableType5.getGeneric(1, 0).resolve();
4、得到构造器参数的泛型信息
假设我们的构造器如下:
public Const(List<List<String>> list, Map<String, Map<String, Integer>> map) {
}
我们可以通过如下方式得到第1个参数( Map<String, Map<String, Integer>>)中的Integer:
ResolvableType resolvableType6 = ResolvableType.forConstructorParameter(ClassUtils.getConstructorIfAvailable(Const.class, List.class, Map.class), 1);
resolvableType6.getGeneric(1, 0).resolve();
5、得到数组组件类型的泛型信息
如对于private List<String>[] array; 可以通过如下方式获取List的泛型实参String:
ResolvableType resolvableType7 =
ResolvableType.forField(ReflectionUtils.findField(GenricInjectTest.class, "array"));
// 判断是否是数组[],List通过isArray()会返回false
resolvableType7.isArray();
// getComponentType()获取数组类型泛型
resolvableType7.getComponentType().getGeneric(0).resolve();
6、自定义泛型类型
// 相当于创建一个List<String>类型
ResolvableType resolvableType8 = ResolvableType.forClassWithGenerics(List.class, String.class);
// 相当于创建一个List<String>[]数组;
ResolvableType resolvableType9 = ResolvableType.forArrayComponent(resolvableType8);
// 得到相应的泛型信息;
resolvableType9.getComponentType().getGeneric(0).resolve();
7、泛型等价比较:
isAssignableFrom(),如下创建一个List<Integer>[]数组,与之前的List<String>[]数组比较,将返回false
ResolvableType resolvableType10 = ResolvableType.forClassWithGenerics(List.class, Integer.class);
ResolvableType resolvableType11= ResolvableType.forArrayComponent(resolvableType10);
resolvableType11.getComponentType().getGeneric(0).resolve();
resolvableType7.isAssignableFrom(resolvableType11);
8、向上转化类型
ResolvableType as(Class<?> type),向上取接口或父类
下面我们列举一个List集合向上转化的场景:
static class ExtendsList extends ArrayList<CharSequence> {
}
@Test
public void asTest() throws Exception {
ResolvableType type = ResolvableType.forType(ExtendsList.class);
ResolvableType listType=type.as(ArrayList.class);
System.out.println(listType.getType());
System.out.println(listType.getRawClass());
}
输出结果:
java.util.ArrayList<java.lang.CharSequence>
class java.util.ArrayList
关于ResolvableType的实现原理,我们暂且尚不讨论,ResolvableType的其他API,后续会陆续补充到