Spring 中好用的泛型操作API
随着泛型用的越来越多,获取泛型实际类型信息的需求也会出现,如果用原生API,需要很多步操作才能获取到泛型,比如:
- ParameterizedType parameterizedType =
- (ParameterizedType) ABService.class.getGenericInterfaces()[0];
- Type genericType = parameterizedType.getActualTypeArguments()[1];
Spring提供的ResolvableType API,提供了更加简单易用的泛型操作支持,如:
- ResolvableType resolvableType1 = ResolvableType.forClass(ABService.class);
- resolvableType1.as(Service.class).getGeneric(1).resolve()
对于获取更复杂的泛型操作ResolvableType更加简单。
假设我们的API是:
- 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> {
- }
如上泛型类非常简单。
1、得到类型的泛型信息
- ResolvableType resolvableType1 = ResolvableType.forClass(ABService.class);
通过如上API,可以得到类型的ResolvableType,如果类型被Spring AOP进行了CGLIB代理,请使用ClassUtils.getUserClass(ABService.class)得到原始类型。
可以通过如下得到泛型参数的第1个位置(从0开始)的类型信息
- resolvableType1.getInterfaces()[0].getGeneric(1).resolve()
因为我们泛型信息放在 Service<A, B> 上,所以需要resolvableType1.getInterfaces()[0]得到;
通过getGeneric(泛型参数索引)得到某个位置的泛型;
resolve()把实际泛型参数解析出来
2、得到字段级别的泛型信息
假设我们的字段如下:
- @Autowired
- private Service<A, B> abService;
- @Autowired
- private Service<C, D> cdService;
- private List<List<String>> list;
- private Map<String, Map<String, Integer>> map;
- private List<String>[] array;
通过如下API可以得到字段级别的ResolvableType
- ResolvableType resolvableType2 =
- ResolvableType.forField(ReflectionUtils.findField(GenricInjectTest.class, "cdService"));
然后通过如下API得到Service<C, D>的第0个位置上的泛型实参类型,即C
- resolvableType2.getGeneric(0).resolve()
比如 List<List<String>> list;是一种嵌套的泛型用例,我们可以通过如下操作获取String类型:
- ResolvableType resolvableType3 =
- ResolvableType.forField(ReflectionUtils.findField(GenricInjectTest.class, "list"));
- 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()
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"));
- resolvableType7.isArray();//判断是否是数组
- resolvableType7.getComponentType().getGeneric(0).resolve();
6、自定义泛型类型
- ResolvableType resolvableType8 = ResolvableType.forClassWithGenerics(List.class, String.class);
- ResolvableType resolvableType9 = ResolvableType.forArrayComponent(resolvableType8);
- resolvableType9.getComponentType().getGeneric(0).resolve();
ResolvableType.forClassWithGenerics(List.class, String.class)相当于创建一个List<String>类型;
ResolvableType.forArrayComponent(resolvableType8);:相当于创建一个List<String>[]数组;
resolvableType9.getComponentType().getGeneric(0).resolve():得到相应的泛型信息;
7、泛型等价比较:
- resolvableType7.isAssignableFrom(resolvableType9)
如下创建一个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);
从如上操作可以看出其泛型操作功能十分完善,尤其在嵌套的泛型信息获取上相当简洁。目前整个Spring4环境都使用这个API来操作泛型信息。
如之前说的泛型注入:Spring4新特性——泛型限定式依赖注入,通过在依赖注入时使用如下类实现:
GenericTypeAwareAutowireCandidateResolver
QualifierAnnotationAutowireCandidateResolver
ContextAnnotationAutowireCandidateResolver
还有如Spring的核心BeanWrapperImpl,以及整个Spring/SpringWevMVC的泛型操作都是替换为这个API了:GenericCollectionTypeResolver和GenericTypeResolver都直接委托给ResolvableType这个API。
参考博客:http://jinnianshilongnian.iteye.com/blog/1993608
Spring 中好用的泛型操作API的更多相关文章
- Spring中的JDBC操作
		一.Spring模板JdbcTemplate 为了使 JDBC 更加易于使用, Spring 在 JDBC API 上定义了一个抽象层, 以此建立一个 JDBC 存取框架JdbcTemplate. 作 ... 
- (转)Spring中的事务操作
		http://blog.csdn.net/yerenyuan_pku/article/details/70024364 事务的回顾 什么是事务 事务是逻辑上的一组操作,组成这组操作的各个逻辑单元,要么 ... 
- Spring Boot和Feign中使用Java 8时间日期API(LocalDate等)的序列化问题【转】
		Spring Boot和Feign中使用Java 8时间日期API(LocalDate等)的序列化问题 http://blog.didispace.com/Spring-Boot-And-Feign- ... 
- Spring中的JDBC API
		1 JdbcTemplate的诞生 JDBC作为Java平台访问关系数据库的标准API,其成功是有目共睹的.为了避免在JDBC API在使用中的种种尴尬局面(几乎程式一样的代码,繁琐的异常处理),Sp ... 
- Spring中AOP相关的API及源码解析
		Spring中AOP相关的API及源码解析 本系列文章: 读源码,我们可以从第一行读起 你知道Spring是怎么解析配置类的吗? 配置类为什么要添加@Configuration注解? 谈谈Spring ... 
- java泛型操作复习,以及讲解在android中使用的场景
		android使用泛型的地方很多,比如集成自BaseAdapter实现封装的Adapter,对常用操作进行封装,但是需要对传进来的数据进行处理,此时就使用到泛型,示例如下: public abstra ... 
- Spring中的事务操作
		事务的特性 原子性:强调事务的不可分割. 一致性:事务的执行的前后数据的完整性保持一致. 隔离性:一个事务执行的过程中,不应该受到其他事务的干扰. 持久性:事务一旦结束,数据就持久化到数据库. 如果不 ... 
- Spring 中的事务操作、注解、以及 XML 配置
		事务 事务全称叫数据库事务,是数据库并发控制时的基本单位,它是一个操作集合,这些操作要么不执行,要么都执行,不可分割.例如我们的转账这个业务,就需要进行数据库事务的处理. 转账中至少会涉及到两条 SQ ... 
- spring对数据库的操作、spring中事务管理的介绍与操作
		jdbcTemplate的入门 创建maven工程 此处省略 导入依赖 <!-- https://mvnrepository.com/artifact/org.springframework/s ... 
随机推荐
- MQTT的学习研究(二)moquette-mqtt 的使用之mqtt broker的启动
			在MQTT 官网 (http://mqtt.org/software)中有众多MQTT的实现方式.具体参看官网,Moquette是基于Apache Mina 的模型的一个Java MQTT broke ... 
- Lucene构建索引时的一些概念和索引构建的过程
			在搜索文档内容之前要做的事情就是对从各种不同来源(网页,数据库,电子邮件等)的文档进行索引,索引的过程就是对内容进行提取,规范化(通过对内容进行建模来实现),然后存储. 在索引的过程中有几个基本的概念 ... 
- 【BZOJ1713】[Usaco2007 China]The Bovine Accordion and Banjo Orchestra 音乐会 斜率优化
			[BZOJ1713][Usaco2007 China]The Bovine Accordion and Banjo Orchestra 音乐会 Description Input 第1行输入N,之后N ... 
- Android 使用动画效果后的控件位置处理 类似系统通知栏下拉动画
			Android的动画的使用,请参考.Android的动画,在设计方面,我有点不太理解,觉得这样搞很怪,因为在控件动画后,即使设置了停留在动画结束时的位置,我们也确实看到了控件停在那个位置,但其实该控件 ... 
- Java 中编程的格式
			Java 编程注意的格式: 1.大括号对齐 2.遇到{ 缩进Tab 3.程序块之间加空行 4.并排之间加空格 5.运算符之间加空格 6.{ 之间加空格 7.成对编程 ({ }) 8.类名首字母大写 9 ... 
- yii2 controller发送json数据给前端
			最近要用yii2把之前老项目重构一下,因为前端打算用vuejs,所以Yii2前端那一套就放弃了,直接给前端传json数据 控制器代码: $response = Yii::$app->respon ... 
- Servlet + JSP 时代
			Spring,Django,Rails,Express这些框架技术的出现都是为了解决什么问题,现在这些框架都应用在哪些方面? - 知乎 https://www.zhihu.com/question/2 ... 
- Python性能鸡汤(转)
			英文原文:http://blog.monitis.com/index.php/2012/02/13/python-performance-tips-part-1/ 英文原文:http://blog.m ... 
- C++ Design Pattern: What is a Design Pattern?
			Q: What is a Design Pattern? A: Design Patterns represent solutions to problems what arise when deve ... 
- 【新业务搭建】竞争情报业务规划及体系构建的思考——By Team
			竞争情报业务规划.体系构建 一.竞争情报业务定位——“做什么” 一)业务愿景.目标和原则 愿景:将情报工作融入到公司各个业务中,成为业务活动的灯塔 目标:直接支撑标杆学习(间接支撑三大战略).直接支持 ... 
