获取指定包中的class和获取class中的所有注解的值,封装性很不错
关注github:https://github.com/zhangpeibisha
目前Java中使用注解来完成一些业务十分方便,因此我们急需一些能够读取类信息和获取类中的指定的注解的详细信息。
以下是我封装了的方法:
1.ScanPack 用来扫描指定包中的文件(包括jar、java、class)
package org.nix.book.common.utils.scan;import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;/*** Create by zhangpe0312@qq.com on 2018/6/3.*/
public class ScanPack {private ScanPack(){}/*** 从包package中获取所有的Class** @param pack 指定扫描的包* @return 包里面的所有文件*/public static Set> getClasses(String pack) {// 第一个class类的集合Set> classes = new LinkedHashSet>();// 是否循环迭代boolean recursive = true;// 获取包的名字 并进行替换String packageName = pack;String packageDirName = packageName.replace('.', '/');// 定义一个枚举的集合 并进行循环来处理这个目录下的thingsEnumeration dirs;try {dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);// 循环迭代下去while (dirs.hasMoreElements()) {// 获取下一个元素URL url = dirs.nextElement();// 得到协议的名称String protocol = url.getProtocol();// 如果是以文件的形式保存在服务器上if ("file".equals(protocol)) {System.err.println("file类型的扫描");// 获取包的物理路径String filePath = URLDecoder.decode(url.getFile(), "UTF-8");// 以文件的方式扫描整个包下的文件 并添加到集合中findAndAddClassesInPackageByFile(packageName, filePath,recursive, classes);} else if ("jar".equals(protocol)) {// 如果是jar包文件// 定义一个JarFileSystem.err.println("jar类型的扫描");JarFile jar;try {// 获取jarjar = ((JarURLConnection) url.openConnection()).getJarFile();// 从此jar包 得到一个枚举类Enumeration entries = jar.entries();// 同样的进行循环迭代while (entries.hasMoreElements()) {// 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件JarEntry entry = entries.nextElement();String name = entry.getName();// 如果是以/开头的if (name.charAt(0) == '/') {// 获取后面的字符串name = name.substring(1);}// 如果前半部分和定义的包名相同if (name.startsWith(packageDirName)) {int idx = name.lastIndexOf('/');// 如果以"/"结尾 是一个包if (idx != -1) {// 获取包名 把"/"替换成"."packageName = name.substring(0, idx).replace('/', '.');}// 如果可以迭代下去 并且是一个包if ((idx != -1) || recursive) {// 如果是一个.class文件 而且不是目录if (name.endsWith(".class")&& !entry.isDirectory()) {// 去掉后面的".class" 获取真正的类名String className = name.substring(packageName.length() + 1, name.length() - 6);try {// 添加到classesclasses.add(Class.forName(packageName + '.'+ className));} catch (ClassNotFoundException e) {// log// .error("添加用户自定义视图类错误 找不到此类的.class文件");e.printStackTrace();}}}}}} catch (IOException e) {// log.error("在扫描用户定义视图时从jar包获取文件出错");e.printStackTrace();}}}} catch (IOException e) {e.printStackTrace();}return classes;}/*** 以文件的形式来获取包下的所有Class** @param packageName 包的名字* @param packagePath 包的路径* @param recursive* @param classes 文件列表*/public static void findAndAddClassesInPackageByFile(String packageName,String packagePath,final boolean recursive,Set> classes) {// 获取此包的目录 建立一个FileFile dir = new File(packagePath);// 如果不存在或者 也不是目录就直接返回if (!dir.exists() || !dir.isDirectory()) {// log.warn("用户定义包名 " + packageName + " 下没有任何文件");return;}// 如果存在 就获取包下的所有文件 包括目录File[] dirfiles = dir.listFiles(new FileFilter() {// 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)public boolean accept(File file) {return (recursive && file.isDirectory())|| (file.getName().endsWith(".class"));}});// 循环所有文件for (File file : dirfiles) {// 如果是目录 则继续扫描if (file.isDirectory()) {findAndAddClassesInPackageByFile(packageName + "."+ file.getName(), file.getAbsolutePath(), recursive,classes);} else {// 如果是java类文件 去掉后面的.class 只留下类名String className = file.getName().substring(0,file.getName().length() - 6);try {// 添加到集合中去//classes.add(Class.forName(packageName + '.' + className));//经过回复同学的提醒,这里用forName有一些不好,会触发static方法,没有使用classLoader的load干净classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className));} catch (ClassNotFoundException e) {// log.error("添加用户自定义视图类错误 找不到此类的.class文件");e.printStackTrace();}}}}}
2.自定义 KeepAnnotation类来保存注解信息
package org.nix.book.common.utils.scan;import java.lang.annotation.Annotation;
import java.util.Map;/*** Create by zhangpe0312@qq.com on 2018/6/3.** 用来保存扫描到的注解集合*/
public class KeepAnnotation {private Class classzz;private Annotation classzzAnnotation;private Map methodAnnotation;public KeepAnnotation(Class classzz) {this.classzz = classzz;}public Class getClasszz() {return classzz;}public void setClasszz(Class classzz) {this.classzz = classzz;}public Annotation getClasszzAnnotation() {return classzzAnnotation;}public void setClasszzAnnotation(Annotation classzzAnnotation) {this.classzzAnnotation = classzzAnnotation;}public Map getMethodAnnotation() {return methodAnnotation;}public void setMethodAnnotation(Map methodAnnotation) {this.methodAnnotation = methodAnnotation;}@Overridepublic String toString() {return "KeepAnnotation{" +"classzz=" + classzz +", classzzAnnotation=" + classzzAnnotation +", methodAnnotation=" + methodAnnotation +'}';}
}
3. 定义扫描注解工具类 ScanAnnotation
package org.nix.book.common.utils.scan;import org.nix.book.entity.book.Book;import javax.persistence.Column;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;/*** Create by zhangpe0312@qq.com on 2018/6/3.* * 扫描指定包的注解*/
public class ScanAnnotation {/*** 查询指定包中的类的所有注解* @param packagePath 指定包路径* @param annotation 需要查询的注解* @param checkRepeat 是否查重* @return 注解集合* @throws Exception 如果有两个方法上的两个注解完全相同时则抛出异常*/public static List getAnnotationByPackage(String packagePath, Class extends Annotation> annotation, boolean checkRepeat) throws Exception {Set> classes = ScanPack.getClasses(packagePath);List keepAnnotations = new ArrayList<>(classes.size());for (Class classzz : classes) {KeepAnnotation keepAnnotation = getAnnotationByClass(classzz, annotation, checkRepeat);keepAnnotations.add(keepAnnotation);}return keepAnnotations;}/*** 查找一个类上的所有注解** @param classzz 指定查找的类* @param annotation 需要获取的注解* @param checkRepeat 是否查找重复的注解* @return 注解集合* @throws Exception 如果有两个方法上的两个注解完全相同时则抛出异常*/public static KeepAnnotation getAnnotationByClass(Class> classzz, Class extends Annotation> annotation, boolean checkRepeat) throws Exception {KeepAnnotation KeepAnnotation = new KeepAnnotation(classzz);// 获取到类上的注解Annotation classzzAnnotation = classzz.getAnnotation(annotation);if (classzzAnnotation != null) KeepAnnotation.setClasszzAnnotation(classzzAnnotation);// 获取到方法上的注解Map methodAnnotations = new HashMap<>();Method[] methods = classzz.getMethods();for (Method method : methods) {Annotation methodAnnotation = method.getAnnotation(annotation);if (methodAnnotation != null) {// 如果需要检查重复则检查否则不检测注解值是否重复if (checkRepeat && methodAnnotations.containsValue(methodAnnotation))throw new Exception(classzz.getName() + " \n" + method.getName() + " \n"+ methodAnnotation.toString() + " have repeat value");else {methodAnnotations.put(method.getName(),methodAnnotation);}}}KeepAnnotation.setMethodAnnotation(methodAnnotations);return KeepAnnotation;}public static void main(String[] args) throws Exception {
// Set> classes = ScanPack.getClasses("");KeepAnnotation KeepAnnotation = getAnnotationByClass(Book.class, Column.class, false);System.out.println();}
}
Over,现在可以完成自己需要使用注解来实现的具体功能了。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
