java扫描指定package注解_java随笔-扫描使用指定注解的类与方法

前几天项目中让扫描出所有使用Restful API的方法。刚开始还想着用python过滤关键字来查找的,后来想想可以使用反射来搞的。主要包含以下三个步骤:

根据包名解析包的具体路径

查找指定包下指定注解的类

在上一步骤中得到的类中,依次扫描包含指定注解的方法

想着写着工具类的形式,代码结构如下:

public class AnnotationScannerUtils {

private static final Logger logger = LoggerFactory.getLogger(AnnotationScannerUtils.class);

private static final String EXT = "class

/**

* 根据包名获取包的URL

* @param pkgName com.demo.controller

* @return

*/

public static String getPkgPath(String pkgName){

String pkgDirName = pkgName.replace('.', File.separatorChar);

URL url = Thread.currentThread().getContextClassLoader().getResource(pkgDirName);

return url == null ? null : url.getFile();

}

/**

* 获取指定包下所有类对象的集合

* @param pkgName 包名(com.demo.controller)

* @param pkgPath 包路径(/Users/xxx/workspace/java/project/out/production/classes/com/demo/controller)

* @param recursive 是否递归遍历子目录

* @return 类集合

*/

public static Set> scanClasses(String pkgName, String pkgPath, final boolean recursive){

Set> classesSet = new HashSet<>();

Collection allClassFile = getAllClassFile(pkgPath, recursive);

for (File curFile : allClassFile){

try {

classesSet.add(getClassObj(curFile, pkgPath, pkgName));

} catch (ClassNotFoundException e) {

logger.error("load class fail", e);

}

}

return classesSet;

}

/**

* 获取指定包下包含指定注解的所有类对象的集合

* @param pkgName 包名(com.demo.controller)

* @param pkgPath 包路径(/Users/xxx/workspace/java/project/out/production/classes/com/demo/controller)

* @param recursive 是否递归遍历子目录

* @param targetAnnotations 指定注解

* @return 以注解和对应类集合构成的键值对

*/

public static Map, Set>> scanClassesByAnnotations(

String pkgName, String pkgPath, final boolean recursive, List> targetAnnotations){

Map, Set>> resultMap = new HashMap<>(16);

Collection allClassFile = getAllClassFile(pkgPath, recursive);

for (File curFile : allClassFile){

try {

Class> curClass = getClassObj(curFile, pkgPath, pkgName);

for (Class extends Annotation> annotation : targetAnnotations){

if (curClass.isAnnotationPresent(annotation)){

if (!resultMap.containsKey(annotation)){

resultMap.put(annotation, new HashSet>());

}

resultMap.get(annotation).add(curClass);

}

}

} catch (ClassNotFoundException e) {

logger.error("load class fail", e);

}

}

return resultMap;

}

/**

* 加载类

* @param file

* @param pkgPath

* @param pkgName

* @return

* @throws ClassNotFoundException

*/

private static Class> getClassObj(File file, String pkgPath, String pkgName) throws ClassNotFoundException{

// 考虑class文件在子目录中的情况

String absPath = file.getAbsolutePath().substring(0, file.getAbsolutePath().length() - EXT.length() - 1);

String className = absPath.substring(pkgPath.length()).replace(File.separatorChar, '.');

className = className.startsWith(".") ? pkgName + className : pkgName + "." + className;

return Thread.currentThread().getContextClassLoader().loadClass(className);

}

/**

* 遍历指定目录下所有扩展名为class的文件

* @param pkgPath 包目录

* @param recursive 是否递归遍历子目录

* @return

*/

private static Collection getAllClassFile(String pkgPath, boolean recursive){

File fPkgDir = new File(pkgPath);

if (!(fPkgDir.exists() && fPkgDir.isDirectory())){

logger.error("the directory to package is empty: {}", pkgPath);

return null;

}

return FileUtils.listFiles(fPkgDir, new String[]{EXT}, recursive);

}

/**

* 查找指定注解的Method

* @param classes 查找范围

* @param targetAnnotations 指定的注解

* @return 以注解和对应Method类集合构成的键值对

*/

public static Map, Set> scanMethodsByAnnotations(Set> classes,

List> targetAnnotations){

Map, Set> resultMap = new HashMap<>(16);

for (Class> cls : classes){

Method[] methods = cls.getMethods();

for (Class extends Annotation> annotation : targetAnnotations){

for (Method method : methods){

if (method.isAnnotationPresent(annotation)){

if (!resultMap.containsKey(annotation)){

resultMap.put(annotation, new HashSet());

}

resultMap.get(annotation).add(method);

}

}

}

}

return resultMap;

}

}

复制代码

具体使用时,可根据具体情况在原方法上二次开发。如果是直接调用,可以实现扫描包含指定注解的类和方法:

public static void main(String[] args){

String pkgName = "com.demo.controller";

String pkgPath = getPkgPath(pkgName);

logger.info("pkgPath is {}", pkgName);

// 查找包含RestController和Controller注解的类

Map, Set>> classesMap = scanClassesByAnnotations(pkgName, pkgPath, true,

Arrays.asList(RestController.class, Controller.class));

if (classesMap.size() == 0){

logger.error("Not exists any class in {} with the specified annotation", pkgPath);

return;

}

Set> classSet = new HashSet<>();

classesMap.forEach((k, v) -> {

logger.info("get {} classes with {}", v.size(), k.getSimpleName());

classSet.addAll(v);

});

// 查找包含GetMapping和PostMapping注解的Method

Map, Set> methodMap = scanMethodsByAnnotations(classSet, Arrays.asList(GetMapping.class, PostMapping.class));

if (methodMap.size() == 0){

logger.error("Not exists any method with the specified annotation");

return;

}

methodMap.forEach((k, v) -> {

StringBuilder sb = new StringBuilder();

v.forEach(method -> sb.append(method.getName()+", "));

logger.info(k.getSimpleName() + ": " + sb.toString());

});

}

--------------------------output-------------------------

01-20 15:06:02.293 [ INFO] [ m.i.u.AnnotationScannerUtils: 29] - pkgPath is com.demo.controller

01-20 15:06:02.363 [ INFO] [ m.i.u.AnnotationScannerUtils: 41] - get 5 classes with RestController

01-20 15:06:02.374 [ INFO] [ m.i.u.AnnotationScannerUtils: 41] - get 2 classes with Controller

01-20 15:06:02.388 [ INFO] [ m.i.u.AnnotationScannerUtils: 55] - PostMapping: login, addFavorite, addUser, logout,

01-20 15:06:02.388 [ INFO] [ m.i.u.AnnotationScannerUtils: 55] - GetMapping: webSiteInfo, info, getCategories, favoritesList, getReportByCityId, queryUserById, getReportByCityName, queryBookById,

复制代码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/263958.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

windows mobile开发循序渐进(6)windows mobile device center 使用问题

由于个人中邪&#xff0c;在经历一次windows 7安装失败之后&#xff0c;贼心不死&#xff0c;于昨天又重新安装了windows 7&#xff0c;终于成功。 回到windows mobile的开发上来呢&#xff0c;首先是配置环境&#xff0c;按照之前的经验&#xff0c;比较顺利的安装了virtual p…

Python---基础---list(列表)

2019-05-20 一、 # append() 向列表末尾追加新元素 返回值Nonelist1 [1,2,3,4,5]print(id(list1))list1.append(6)print(id(list1)) 二、 #copy() 复制列表list1 [1,2,3,4,5]list2 list1.copy()print(list2)print(id(list1))print(id(list2)) 三、 #count() 计算某个元素…

mysql if selected_初识MySQL

安装下载地址&#xff1a;https://dev.mysql.com/downloads/mysql/​dev.mysql.com双击.msi文件开始安装&#xff0c;采用Custom安装方式。配置安装完毕弹出配置&#xff0c;或者安装路径下bin文件夹下MySQLInstanceConfig.exe运行可以进行配置。采用Detailed Configuration-》…

VisualC++2010系列课程

VisualC2010系列课程&#xff0c; 请访问博客http://blog.csdn.net/yincheng01 &#xff08;基于Visual C2010与windows SDK fo windows7开发Windows 7超级任务栏应用程序http://blog.csdn.net/yincheng01/archive/2009/12/27/5086755.aspx基于Visual C2010与windows SDK fo wi…

【MongoDB学习笔记21】MongoDB的复合索引

索引的值是按照一定顺序排列的&#xff0c;因此使用索引键对文档进行搜索排序比较快&#xff1b;但是只有首先使用索引进行排序时&#xff0c;索引才有用&#xff1b;例如下面的排序里&#xff0c;“username”上的索引就没有起作用&#xff1a;> db.users.find().sort({&qu…

mysql 代理 a_Keepalived+Mysql+Haproxy

#dd dd0 配主从vi /etc/my.cnf[mysqld]server-id 1log-bin mysql-binbinlog-ignore-db mysql,information_schemabinlog_format mixedauto-increment-increment 2auto-increment-offset 1#ddgrant replication slave on *.* to dd192.168.55.% identified by 123456show …

你真的了解Ioc与AOP 吗?(2)

三、基于配置文件和Reflection的工厂模式 为了消除MainApp对其它组件的依赖性&#xff0c;我们引入工厂模式&#xff0c;并且根据配置文件指定的装配规程&#xff0c;利用.net提供的反射技术完成对象的组装工作。本部分代码仅仅提供一种功能演示&#xff0c;如果实际应用仍需进…

DataTime转Varchar

SELECT Convert(varchar(100),A.CreateTime,20) FROM [TB_Business_Award] A 转载于:https://www.cnblogs.com/Anthony518/p/10908263.html

关于一道数据库例题的解析。为什么σ age22 (πS_ID,SCORE (SC) ) 选项是错的?

本人大二学子。近段时间在做数据库复习题的时候遇到一道题&#xff0c;如下。 有关系SC&#xff08;S_ID&#xff0c;C_ID&#xff0c;AGE&#xff0c;SCORE&#xff09;&#xff0c;查找年龄大于22岁的学生的学号和分数&#xff0c;正确的关系代数表达式是&#xff08; &#…

砂.随笔.二十五.如果你是氧气

在跌倒的地方 勇敢站起来 我在这里 在纯真的梦里转载于:https://www.cnblogs.com/aque1984/archive/2010/05/07/1729361.html

java获取表主外键_通过 jdbc 分析数据库中的表结构和主键外键

文章转自&#xff1a;http://ivan4126.blog.163.com/blog/static/20949109220137753214811/在某项目中用到了 hibernate &#xff0c;大家都知道 hibernate 是 ORM 框架&#xff0c;他是有能力根据实体生成数据库表的。我们在单元测试的时候用到了 dbUnit &#xff0c;dbUnit 可…

OO第三单元总结:JML

目录 第三单元——jml、junit与图第三单元——jml、junit与图 〇、问题描述 ​ 本单元主题为JML的学习&#xff0c;问题载体为一个无向图路径管理系统。在三次作业种&#xff0c;情景不变&#xff0c;需求递增。因此需要在层次上做好安排。 一、JML语言 理论基础(Level 0) 注释…

沼跃鱼早已看穿了一切 C/C++

沼跃鱼早已看穿了一切 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 593 Solved: 229[Submit][Status][Web Board]Description 沼跃鱼打开密码门后发现门后是一个像迷宫一样的房间&#xff0c;墙上的指示牌写着&#xff1a;房间内某处有一宝箱&#xff0c;但是宝箱被上锁了…

c#扩展方法奇思妙用高级篇四:对扩展进行分组管理

从系列文章开篇到现在&#xff0c;已经实现的很多扩展了&#xff0c;但过多的扩展会给我们带来很多麻烦&#xff0c;试看下图&#xff1a; 面对这么多“泛滥”的扩展&#xff0c;很多人都会感到很别扭&#xff0c;的确有种“喧宾夺主”的感觉&#xff0c;想从中找出真正想用的方…

js 获取java_js中获取当前时间

var d new Date();var date d.getFullYear() "年" (d.getMonth() 1) "月" d.getDate() "日";var myDate new Date();myDate.getYear(); //获取当前年份(2位)myDate.getFullYear(); //获取完整的年份(4位,1970-????)myDate…

Robot Framework-Ride界面介绍及库的添加

Ride界面介绍1. Ride简介1.1什么是RideRide是robotframework的UI界面, 以HTML格式提供易于阅读的结果报告和日志, 用户可以自定义基于Python的测试库, 提供支持selenium的Web测试,语法和python很像。1.2 Ride界面介绍1.2.1主界面介绍&#xff1a; 1.2.2运行按钮和工程目录&a…

preloadlazy load

最近需要用到预加载和延迟加载的东东&#xff0c;就参考写了一个。 支持跨页面&#xff0c;支持超时设置与依赖设置。 (function($) { (function($) {$.preload function(data, cfg) {return new Loader(data, cfg);};var maps {}, on $.event.add, un $.event.remove, hea…

Android项目实战(三):实现第一次进入软件的引导页

最近做的APP接近尾声了&#xff0c;就是些优化工作了&#xff0c; 我们都知道现在的APP都会有引导页&#xff0c;就是安装之后第一次打开才显示的引导页面&#xff08;介绍这个软件的几张可以切换的图&#xff09; 自己做了一下&#xff0c;结合之前学过的 慕课网_ViewPager切换…

java gettime_Java Util.getTime方法代码示例

import org.jrobin.core.Util; //导入方法依赖的package包/类private void initGraphPeriodAndSize(Range range, int width, int height, RrdGraphDef graphDef) {// ending timestamp is the (current) timestamp in seconds// starting timestamp will be adjusted for each…

LESS CSS 框架简介(转)

为什么80%的码农都做不了架构师&#xff1f;>>> 原文地址:http://www.ibm.com/developerworks/cn/web/1207_zhaoch_lesscss/ 简介 CSS&#xff08;层叠样式表&#xff09;是一门历史悠久的标记性语言&#xff0c;同 HTML 一道&#xff0c;被广泛应用于万维网&#…