Class类工具 - ClassUtils.java

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Class类工具 - ClassUtils.java相关的知识,希望对你有一定的参考价值。

Class类工具,提供操作class类的方法。<br/>
比如:获知类、方法上是否有注解,获取类注解,获取某package下所有class等。

 

源码如下:(点击下载 - 技术分享ClassUtils.java )

  1 import java.io.File;
  2 import java.io.FileFilter;
  3 import java.io.IOException;
  4 import java.lang.annotation.Annotation;
  5 import java.lang.reflect.Field;
  6 import java.lang.reflect.Method;
  7 import java.net.JarURLConnection;
  8 import java.net.URL;
  9 import java.net.URLDecoder;
 10 import java.util.ArrayList;
 11 import java.util.Enumeration;
 12 import java.util.LinkedHashSet;
 13 import java.util.List;
 14 import java.util.Set;
 15 import java.util.jar.JarEntry;
 16 import java.util.jar.JarFile;
 17 
 18 /**
 19  * Class类工具
 20  * 
 21  */
 22 public class ClassUtils {
 23 
 24     /**
 25      * 是否有注解
 26      *
 27      * @param clazz
 28      *            a {@link java.lang.Class} object.
 29      * @param annotationClass
 30      *            a {@link java.lang.Class} object.
 31      * @return a boolean.
 32      */
 33     public static boolean hasClassAnnotation(Class<?> clazz, Class<? extends Annotation> annotationClass) {
 34         return getClassAnnotation(clazz, annotationClass) != null;
 35     }
 36 
 37     /**
 38      * 是否有注解
 39      *
 40      * @param clazz
 41      *            a {@link java.lang.Class} object.
 42      * @param annotationClass
 43      *            a {@link java.lang.Class} object.
 44      * @param fieldName
 45      *            a {@link java.lang.String} object.
 46      * @throws cn.yicha.commons.exception.YichaException
 47      *             if any.
 48      * @return a boolean.
 49      */
 50     public static boolean hasFieldAnnotation(Class<?> clazz,
 51             Class<? extends Annotation> annotationClass, String fieldName) throws Exception {
 52         return getFieldAnnotation(clazz, annotationClass, fieldName) != null;
 53     }
 54 
 55     /**
 56      * 是否有注解
 57      *
 58      * @param clazz
 59      *            a {@link java.lang.Class} object.
 60      * @param annotationClass
 61      *            a {@link java.lang.Class} object.
 62      * @param methodName
 63      *            a {@link java.lang.String} object.
 64      * @param paramType
 65      *            a {@link java.lang.Class} object.
 66      * @throws cn.yicha.commons.exception.YichaException
 67      *             if any.
 68      * @return a boolean.
 69      */
 70     public static boolean hasMethodAnnotation(Class<?> clazz,
 71             Class<? extends Annotation> annotationClass, String methodName, Class<?>... paramType) throws Exception {
 72         return getMethodAnnotation(clazz, annotationClass, methodName, paramType) != null;
 73     }
 74 
 75     /**
 76      * 获取类注解
 77      *
 78      * @param clazz
 79      *            类
 80      * @param annotationClass
 81      *            注解类
 82      * @return a A object.
 83      */
 84     public static <A extends Annotation> A getClassAnnotation(Class<?> clazz, Class<A> annotationClass) {
 85         return clazz.getAnnotation(annotationClass);
 86     }
 87 
 88     /**
 89      * 获取类成员注解
 90      *
 91      * @param clazz
 92      *            类
 93      * @param annotationClass
 94      *            注解类
 95      * @param fieldName
 96      *            成员属性名
 97      * @throws cn.yicha.commons.exception.YichaException
 98      *             if any.
 99      * @return a A object.
100      */
101     public static <A extends Annotation> A getFieldAnnotation(Class<?> clazz,
102             Class<A> annotationClass, String fieldName) throws Exception {
103         try {
104             Field field = clazz.getDeclaredField(fieldName);
105             if (field == null) {
106                 throw new Exception("no such field[" + fieldName + "] in " + clazz.getCanonicalName());
107             }
108             return field.getAnnotation(annotationClass);
109         } catch (SecurityException e) {
110             e.printStackTrace();
111             throw new Exception("access error: field[" + fieldName + "] in " + clazz.getCanonicalName(), e);
112         } catch (NoSuchFieldException e) {
113             e.printStackTrace();
114             throw new Exception("no such field[" + fieldName + "] in " + clazz.getCanonicalName());
115         }
116     }
117 
118     /**
119      * 获取类方法上的注解
120      *
121      * @param clazz
122      *            类
123      * @param annotationClass
124      *            注解类
125      * @param methodName
126      *            方法名
127      * @param paramType
128      *            方法参数
129      * @throws cn.yicha.commons.exception.YichaException
130      *             if any.
131      * @return a A object.
132      */
133     public static <A extends Annotation> A getMethodAnnotation(Class<?> clazz,
134             Class<A> annotationClass, String methodName, Class<?>... paramType)
135             throws Exception {
136         try {
137             Method method = clazz.getDeclaredMethod(methodName, paramType);
138             if (method == null) {
139                 throw new Exception("access error: method[" + methodName + "] in " + clazz.getCanonicalName());
140             }
141             return method.getAnnotation(annotationClass);
142         } catch (SecurityException e) {
143             e.printStackTrace();
144             throw new Exception("access error: method[" + methodName + "] in " + clazz.getCanonicalName(), e);
145         } catch (NoSuchMethodException e) {
146             e.printStackTrace();
147             throw new Exception("no such method[" + methodName + "] in " + clazz.getCanonicalName(), e);
148         }
149     }
150 
151     /**
152      * 从包package中获取所有的Class
153      *
154      * @param pagekageName
155      *            包名
156      * @param recursive
157      *            是否递归
158      * @return a {@link java.util.Set} object.
159      */
160     public static Set<Class<?>> getClasses(String pagekageName, boolean recursive) {
161         // 第一个class类的集合
162         Set<Class<?>> classes = new LinkedHashSet<Class<?>>();
163         // 获取包的名字 并进行替换
164         String packageName = pagekageName;
165         String packageDirName = packageName.replace(‘.‘, ‘/‘);
166         // 定义一个枚举的集合 并进行循环来处理这个目录下的things
167         Enumeration<URL> dirs;
168         try {
169             dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
170             // 循环迭代下去
171             while (dirs.hasMoreElements()) {
172                 // 获取下一个元素
173                 URL url = dirs.nextElement();
174                 // 得到协议的名称
175                 String protocol = url.getProtocol();
176                 // 如果是以文件的形式保存在服务器上
177                 if ("file".equals(protocol)) {
178                     // 获取包的物理路径
179                     String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
180                     // 以文件的方式扫描整个包下的文件 并添加到集合中
181                     findAndAddClassesInPackageByFile(packageName, filePath, recursive, classes);
182                 } else if ("jar".equals(protocol)) {
183                     // 如果是jar包文件
184                     // 定义一个JarFile
185                     JarFile jar;
186                     try {
187                         // 获取jar
188                         jar = ((JarURLConnection) url.openConnection()).getJarFile();
189                         // 从此jar包 得到一个枚举类
190                         Enumeration<JarEntry> entries = jar.entries();
191                         // 同样的进行循环迭代
192                         while (entries.hasMoreElements()) {
193                             // 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件
194                             JarEntry entry = entries.nextElement();
195                             String name = entry.getName();
196                             // 如果是以/开头的
197                             if (name.charAt(0) == ‘/‘) {
198                                 // 获取后面的字符串
199                                 name = name.substring(1);
200                             }
201                             // 如果前半部分和定义的包名相同
202                             if (name.startsWith(packageDirName)) {
203                                 int idx = name.lastIndexOf(‘/‘);
204                                 // 如果以"/"结尾 是一个包
205                                 if (idx != -1) {
206                                     // 获取包名 把"/"替换成"."
207                                     packageName = name.substring(0, idx)
208                                             .replace(‘/‘, ‘.‘);
209                                 }
210                                 // 如果可以迭代下去 并且是一个包
211                                 if ((idx != -1) || recursive) {
212                                     // 如果是一个.class文件 而且不是目录
213                                     if (name.endsWith(".class") && !entry.isDirectory()) {
214                                         // 去掉后面的".class" 获取真正的类名
215                                         String className = name.substring(packageName.length() + 1, name.length() - 6);
216                                         try {
217                                             // 添加到classes
218                                             classes.add(Class.forName(packageName + ‘.‘ + className));
219                                         } catch (ClassNotFoundException e) {
220                                             e.printStackTrace();
221                                             // log
222                                             // .error("添加用户自定义视图类错误 找不到此类的.class文件");
223                                         }
224                                     }
225                                 }
226                             }
227                         }
228                     } catch (IOException e) {
229                         // log.error("在扫描用户定义视图时从jar包获取文件出错");
230                         throw new RuntimeException(e);
231                     }
232                 }
233             }
234         } catch (IOException e) {
235             e.printStackTrace();
236         }
237 
238         return classes;
239     }
240 
241     /**
242      * 以文件的形式来获取包下的所有Class
243      *
244      * @param packageName
245      *            a {@link java.lang.String} object.
246      * @param packagePath
247      *            a {@link java.lang.String} object.
248      * @param recursive
249      *            a boolean.
250      * @param classes
251      *            a {@link java.util.Set} object.
252      */
253     public static void findAndAddClassesInPackageByFile(String packageName,
254             String packagePath, final boolean recursive, Set<Class<?>> classes) {
255         // 获取此包的目录 建立一个File
256         File dir = new File(packagePath);
257         // 如果不存在或者 也不是目录就直接返回
258         if (!dir.exists() || !dir.isDirectory()) {
259             // log.warn("用户定义包名 " + packageName + " 下没有任何文件");
260             return;
261         }
262         // 如果存在 就获取包下的所有文件 包括目录
263         File[] dirfiles = dir.listFiles(new FileFilter() {
264             // 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)
265             public boolean accept(File file) {
266                 return (recursive && file.isDirectory()) || (file.getName().endsWith(".class"));
267             }
268         });
269         // 循环所有文件
270         for (File file : dirfiles) {
271             // 如果是目录 则继续扫描
272             if (file.isDirectory()) {
273                 findAndAddClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, classes);
274             } else {
275                 // 如果是java类文件 去掉后面的.class 只留下类名
276                 String className = file.getName().substring(0, file.getName().length() - 6);
277                 try {
278                     // 添加到集合中去
279                     classes.add(Class.forName(packageName + ‘.‘ + className));
280                 } catch (ClassNotFoundException e) {
281                     // log.error("添加用户自定义视图类错误 找不到此类的.class文件");
282                     e.printStackTrace();
283                 }
284             }
285         }
286     }
287 
288     /**
289      * <p>
290      * Description:给一个接口,返回这个接口同一个包下的所有实现类
291      * </p>
292      *
293      * @param c
294      *            a {@link java.lang.Class} object.
295      * @return a {@link java.util.List} object.
296      */
297     public static List<Class<?>> getAllClassByInterface(Class<?> c) {
298         List<Class<?>> returnClassList = new ArrayList<Class<?>>(); // 返回结果
299         // 如果不是一个接口,则不做处理
300         if (!c.isInterface()) {
301             return returnClassList;
302         }
303         String packageName = c.getPackage().getName(); // 获得当前的包名
304         Set<Class<?>> allClass = getClasses(packageName, true); // 获得当前包下以及子包下的所有类
305         // 判断是否是同一个接口
306         for (Class<?> clazz : allClass) {
307             if (c.isAssignableFrom(clazz)) { // 判断是不是一个接口
308                 if (!c.equals(clazz)) { // 本身不加进去
309                     returnClassList.add(clazz);
310                 }
311             }
312         }
313         return returnClassList;
314     }
315 
316 }

 

以上是关于Class类工具 - ClassUtils.java的主要内容,如果未能解决你的问题,请参考以下文章

蚂蚁课堂:class工具类

工具类加载外部jar(普通jar和springboot jar)class

C# 中那些常用的工具类(Utility Class)

JSON C# Class Generator ---由json字符串生成C#实体类的工具

JSON C# Class Generator ---由json字符串生成C#实体类的工具

JSON C# Class Generator ---由json字符串生成C#实体类的工具