【Spring】理解ResolvableType API

随着泛型用的越来越多,获取泛型实际类型信息的需求也会出现,如果用原生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,后续会陆续补充到

参考

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值