随着泛型用的越来越多,获取泛型实际类型信息的需求也会出现,如果用原生API,需要很多步操作才能获取到泛型,比如:

  1. ParameterizedType parameterizedType =
  2. (ParameterizedType) ABService.class.getGenericInterfaces()[0];
  3. Type genericType = parameterizedType.getActualTypeArguments()[1];

Spring提供的ResolvableType API,提供了更加简单易用的泛型操作支持,如:

  1. ResolvableType resolvableType1 = ResolvableType.forClass(ABService.class);
  2. resolvableType1.as(Service.class).getGeneric(1).resolve()

对于获取更复杂的泛型操作ResolvableType更加简单。

假设我们的API是:

  1. public interface Service<N, M> {
  2. }
  3. @org.springframework.stereotype.Service
  4. public class ABService implements Service<A, B> {
  5. }
  6. @org.springframework.stereotype.Service
  7. public class CDService implements Service<C, D> {
  8. }

如上泛型类非常简单。

1、得到类型的泛型信息

  1. ResolvableType resolvableType1 = ResolvableType.forClass(ABService.class);

通过如上API,可以得到类型的ResolvableType,如果类型被Spring AOP进行了CGLIB代理,请使用ClassUtils.getUserClass(ABService.class)得到原始类型。

可以通过如下得到泛型参数的第1个位置(从0开始)的类型信息

  1. resolvableType1.getInterfaces()[0].getGeneric(1).resolve()

因为我们泛型信息放在 Service<A, B> 上,所以需要resolvableType1.getInterfaces()[0]得到;

通过getGeneric(泛型参数索引)得到某个位置的泛型;

resolve()把实际泛型参数解析出来

2、得到字段级别的泛型信息

假设我们的字段如下:

  1. @Autowired
  2. private Service<A, B> abService;
  3. @Autowired
  4. private Service<C, D> cdService;
  5. private List<List<String>> list;
  6. private Map<String, Map<String, Integer>> map;
  7. private List<String>[] array;

通过如下API可以得到字段级别的ResolvableType

  1. ResolvableType resolvableType2 =
  2. ResolvableType.forField(ReflectionUtils.findField(GenricInjectTest.class, "cdService"));

然后通过如下API得到Service<C, D>的第0个位置上的泛型实参类型,即C

  1. resolvableType2.getGeneric(0).resolve()

比如 List<List<String>> list;是一种嵌套的泛型用例,我们可以通过如下操作获取String类型:

  1. ResolvableType resolvableType3 =
  2. ResolvableType.forField(ReflectionUtils.findField(GenricInjectTest.class, "list"));
  3. resolvableType3.getGeneric(0).getGeneric(0).resolve();

更简单的写法

  1. resolvableType3.getGeneric(0, 0).resolve(); //List<List<String>> 即String

比如Map<String, Map<String, Integer>> map;我们想得到Integer,可以使用:

  1. ResolvableType resolvableType4 =
  2. ResolvableType.forField(ReflectionUtils.findField(GenricInjectTest.class, "map"));
  3. resolvableType4.getGeneric(1).getGeneric(1).resolve();

更简单的写法

  1. resolvableType4.getGeneric(1, 1).resolve()

3、得到方法返回值的泛型信息

假设我们的方法如下:

  1. private HashMap<String, List<String>> method() {
  2. return null;
  3. }

得到Map中的List中的String泛型实参:

  1. ResolvableType resolvableType5 =
  2. ResolvableType.forMethodReturnType(ReflectionUtils.findMethod(GenricInjectTest.class, "method"));
  3. resolvableType5.getGeneric(1, 0).resolve();

4、得到构造器参数的泛型信息

假设我们的构造器如下:

  1. public Const(List<List<String>> list, Map<String, Map<String, Integer>> map) {
  2. }

我们可以通过如下方式得到第1个参数( Map<String, Map<String, Integer>>)中的Integer:

  1. ResolvableType resolvableType6 =
  2. ResolvableType.forConstructorParameter(ClassUtils.getConstructorIfAvailable(Const.class, List.class, Map.class), 1);
  3. resolvableType6.getGeneric(1, 0).resolve();

5、得到数组组件类型的泛型信息

如对于private List<String>[] array; 可以通过如下方式获取List的泛型实参String:

  1. ResolvableType resolvableType7 =
  2. ResolvableType.forField(ReflectionUtils.findField(GenricInjectTest.class, "array"));
  3. resolvableType7.isArray();//判断是否是数组
  4. resolvableType7.getComponentType().getGeneric(0).resolve();

6、自定义泛型类型

  1. ResolvableType resolvableType8 = ResolvableType.forClassWithGenerics(List.class, String.class);
  2. ResolvableType resolvableType9 = ResolvableType.forArrayComponent(resolvableType8);
  3. resolvableType9.getComponentType().getGeneric(0).resolve();

ResolvableType.forClassWithGenerics(List.class, String.class)相当于创建一个List<String>类型;

ResolvableType.forArrayComponent(resolvableType8);:相当于创建一个List<String>[]数组;

resolvableType9.getComponentType().getGeneric(0).resolve():得到相应的泛型信息;

7、泛型等价比较:

  1. resolvableType7.isAssignableFrom(resolvableType9)

如下创建一个List<Integer>[]数组,与之前的List<String>[]数组比较,将返回false。

  1. ResolvableType resolvableType10 = ResolvableType.forClassWithGenerics(List.class, Integer.class);
  2. ResolvableType resolvableType11= ResolvableType.forArrayComponent(resolvableType10);
  3. resolvableType11.getComponentType().getGeneric(0).resolve();
  4. resolvableType7.isAssignableFrom(resolvableType11);

从如上操作可以看出其泛型操作功能十分完善,尤其在嵌套的泛型信息获取上相当简洁。目前整个Spring4环境都使用这个API来操作泛型信息。

如之前说的泛型注入:Spring4新特性——泛型限定式依赖注入,通过在依赖注入时使用如下类实现:

GenericTypeAwareAutowireCandidateResolver

QualifierAnnotationAutowireCandidateResolver

ContextAnnotationAutowireCandidateResolver

还有如Spring的核心BeanWrapperImpl,以及整个Spring/SpringWevMVC的泛型操作都是替换为这个API了:GenericCollectionTypeResolver和GenericTypeResolver都直接委托给ResolvableType这个API。

参考博客:http://jinnianshilongnian.iteye.com/blog/1993608

Spring 中好用的泛型操作API的更多相关文章

  1. Spring中的JDBC操作

    一.Spring模板JdbcTemplate 为了使 JDBC 更加易于使用, Spring 在 JDBC API 上定义了一个抽象层, 以此建立一个 JDBC 存取框架JdbcTemplate. 作 ...

  2. (转)Spring中的事务操作

    http://blog.csdn.net/yerenyuan_pku/article/details/70024364 事务的回顾 什么是事务 事务是逻辑上的一组操作,组成这组操作的各个逻辑单元,要么 ...

  3. Spring Boot和Feign中使用Java 8时间日期API(LocalDate等)的序列化问题【转】

    Spring Boot和Feign中使用Java 8时间日期API(LocalDate等)的序列化问题 http://blog.didispace.com/Spring-Boot-And-Feign- ...

  4. Spring中的JDBC API

    1 JdbcTemplate的诞生 JDBC作为Java平台访问关系数据库的标准API,其成功是有目共睹的.为了避免在JDBC API在使用中的种种尴尬局面(几乎程式一样的代码,繁琐的异常处理),Sp ...

  5. Spring中AOP相关的API及源码解析

    Spring中AOP相关的API及源码解析 本系列文章: 读源码,我们可以从第一行读起 你知道Spring是怎么解析配置类的吗? 配置类为什么要添加@Configuration注解? 谈谈Spring ...

  6. java泛型操作复习,以及讲解在android中使用的场景

    android使用泛型的地方很多,比如集成自BaseAdapter实现封装的Adapter,对常用操作进行封装,但是需要对传进来的数据进行处理,此时就使用到泛型,示例如下: public abstra ...

  7. Spring中的事务操作

    事务的特性 原子性:强调事务的不可分割. 一致性:事务的执行的前后数据的完整性保持一致. 隔离性:一个事务执行的过程中,不应该受到其他事务的干扰. 持久性:事务一旦结束,数据就持久化到数据库. 如果不 ...

  8. Spring 中的事务操作、注解、以及 XML 配置

    事务 事务全称叫数据库事务,是数据库并发控制时的基本单位,它是一个操作集合,这些操作要么不执行,要么都执行,不可分割.例如我们的转账这个业务,就需要进行数据库事务的处理. 转账中至少会涉及到两条 SQ ...

  9. spring对数据库的操作、spring中事务管理的介绍与操作

    jdbcTemplate的入门 创建maven工程 此处省略 导入依赖 <!-- https://mvnrepository.com/artifact/org.springframework/s ...

随机推荐

  1. 使用openssl生成RSA公钥和私钥对

    在ubuntu上要使用openssl的话需要先进行安装,命令如下: sudo apt-get install openssl 安装完成就可以使用openssl了. 首先需要进入openssl的交互界面 ...

  2. SSL安装方法二:Windows Server 2008安装SSL证书(IIS 7.5)

    SSL证书CSR和CA证书唯一的区别就在:申请证书中的通用名称,具体还要看具体的项目这里只做参考.可以参考SSL安装方法一 背景:IIS 7.5 一.收到SSL证书 仔细阅读邮件 按步骤进行: 1)  ...

  3. 从一个多项目Web工程看Eclipse如何导入Gradle项目

    这里再次说一下为什么我们需要熟悉Gradle构建工具,主要原因就是很多开源项目现在都在改用Gradle作为构建工具.一部分的github上的示例代码也在用Gradle构建,如果还是只能用maven,那 ...

  4. spring cloud多个消费端重复定义feign client问题

    spring cloud消费端调用服务提供者,有两种方式rest+ribbon和Feign,Feign是一个声明式的伪Http客户端更为简单易用,所以我们项目选用Feign作为服务通讯方式 项目有6个 ...

  5. javase---Java反射操作

    1首先认识什么叫反射 正常的情况下,我们操作一个对象,则必须找到这个对象对应的类,然后实例化,然后再做各种操作, 反射的则通过一个对象获取对应的类,然后实例化,然后做各种操作, 2反射的操作步骤 I获 ...

  6. Oracle体系结构之Oracle10gR2体系结构-内存、进程

    oracle体系结构图1 oracle体系结构图2 用户进程(访问oracle的客户端的总称) 工具的使用:sqlplus.pl/sql developer 如何访问数据库: 本机直接通过sock方式 ...

  7. python基础之函数式编程、匿名函数、内置函数

    一 函数式编程 不修改外部状态. 模仿数学里得函数进行编程. 用函数编程写出得代码相当精简. 可读性比较差. 例子: y=2*x+1 x=1 def test(x): return 2*x+1 tes ...

  8. ViewPager添加小圆点

    ViewPager添加小圆点很简单,但是如果是网络图片可能就不太好做了,所以我这里给出一种方法,当然你也可以用其他的 1.主界面xml <?xml version="1.0" ...

  9. SNMP 原理及配置简述 net-snmp-utils net-snmp 第2版基于SNMP 群体名(community name) 第3版引入了安全性更高的访问控制方法 SNMP协议操作只有4种 Apache的php_snmp 模块

    SNMP 原理及配置简述  net-snmp-utils  net-snmp 第2版基于SNMP 群体名(community name) 第3版引入了安全性更高的访问控制方法 SNMP协议操作只有4种 ...

  10. go-003-基础语法

    1.行分隔符 一行代表一个语句结束. 如果一行多个,使用“;”分割,不推荐使用,建议使用默认一行一个语句 2.标识符 标识符用来命名变量.类型等程序实体.一个标识符实际上就是一个或是多个字母(A~Z和 ...