zoukankan      html  css  js  c++  java
  • 遍历指定包名下所有的类(支持jar)(转)

    支持包名下的子包名遍历,并使用Annotation(内注)来过滤一些不必要的内部类,提高命中精度。

    通过Thread.currentThread().getContextClassLoader()获取ClassLoader实例
    将包名转为路径名后,做为参数传给CloassLoader.getResources(),以得到该路径下所有资源的URL;
    通过URL.getProtocol()方法,判断资源是在本地(file:)或是第三方jar包(jar:)内;
    在本地的类直接文件遍历即可;
    第三方jar则通过URL.openConnection()得到JarURLConnection,再通过JarURLConnection.getJarFile()获得JarFile,最后遍历该JarFile的item即可。

    package lab.sodino.clazz;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * Annotation:见http://blog.csdn.net/sodino/article/details/7987888
     * */
    @Target(ElementType.TYPE)//ElementType.TYPE用于标识类、接口(包括内注自身)、枚举
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface author {
        //修饰符仅可为public, protected, private & static的组合
        public static enum AppEnum {
            Web, Client, Service, Undesignated
        };
    
        //public & abstract的组合或默认
        AppEnum type() default AppEnum.Undesignated;
    
        String name() default "unknown";
    
        String webSite() default "N/A";
    }
    package lab.sodino.clazz;
    /**
     * @author Sodino E-mail:sodino@qq.com
     * @version Time:2014年2月10日 下午9:06:55
     */
    @author(name="sodino", webSite="sodino.com")
    public class ClassTestDemo {
    
    }
    package lab.sodino.clazz;
    
    import java.io.File;
    import java.io.FileFilter;
    import java.io.IOException;
    import java.lang.annotation.Annotation;
    import java.net.JarURLConnection;
    import java.net.URL;
    import java.util.ArrayList;
    import java.util.Enumeration;
    import java.util.List;
    import java.util.jar.JarEntry;
    import java.util.jar.JarFile;
    
    /**
     * 用于获取指定包名下的所有类名.<br/>
     * 并可设置是否遍历该包名下的子包的类名.<br/>
     * 并可通过Annotation(内注)来过滤,避免一些内部类的干扰.<br/>
     * 
     * @author Sodino E-mail:sodino@qq.com
     * @version Time:2014年2月10日 下午3:55:59
     */
    public class ClassUtil {
        public static void main(String []args){
            // 标识是否要遍历该包路径下子包的类名
    //        boolean recursive = false;
            boolean recursive = true;
            // 指定的包名
    //        String pkg = "javax.crypto.spec";// 为java/jre6/lib/jce.jar,普通的java工程默认已引用
    //        String pkg = "javax.crypto";
    //        String pkg = "lab.sodino";
            String pkg = "lab.sodino.clazz";
            List list = null;
    //        list = getClassList(pkg, recursive, null);
            // 增加 author.class的过滤项,即可只选出ClassTestDemo
            list = getClassList(pkg, recursive, author.class);
            
            for(int i = 0;i < list.size(); i ++){
                System.out.println(i +":"+list.get(i));
            }
        }
        
        public static List<Class<?>> getClassList(String pkgName , boolean isRecursive, Class<? extends Annotation> annotation) {
            List<Class<?>> classList = new ArrayList<Class<?>>();
            ClassLoader loader = Thread.currentThread().getContextClassLoader();
            try {
                // 按文件的形式去查找
                String strFile = pkgName.replaceAll("\.", "/");
                Enumeration<URL> urls = loader.getResources(strFile);
                while (urls.hasMoreElements()) {
                    URL url = urls.nextElement();
                    if (url != null) {
                        String protocol = url.getProtocol();
                        String pkgPath = url.getPath();
                        System.out.println("protocol:" + protocol +" path:" + pkgPath);
                        if ("file".equals(protocol)) {
                            // 本地自己可见的代码
                            findClassName(classList, pkgName, pkgPath, isRecursive, annotation);
                        } else if ("jar".equals(protocol)) {
                            // 引用第三方jar的代码
                            findClassName(classList, pkgName, url, isRecursive, annotation);
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            
            return classList;
        }
        
        public static void findClassName(List<Class<?>> clazzList, String pkgName, String pkgPath, boolean isRecursive, Class<? extends Annotation> annotation) {
            if(clazzList == null){
                return;
            }
            File[] files = filterClassFiles(pkgPath);// 过滤出.class文件及文件夹
            System.out.println("files:" +((files == null)?"null" : "length=" + files.length));
            if(files != null){
                for (File f : files) {
                    String fileName = f.getName();
                    if (f.isFile()) {
                        // .class 文件的情况
                        String clazzName = getClassName(pkgName, fileName);
                        addClassName(clazzList, clazzName, annotation);
                    } else {
                        // 文件夹的情况
                        if(isRecursive){
                            // 需要继续查找该文件夹/包名下的类
                            String subPkgName = pkgName +"."+ fileName;
                            String subPkgPath = pkgPath +"/"+ fileName;
                            findClassName(clazzList, subPkgName, subPkgPath, true, annotation);
                        }
                    }
                }
            }
        }
        
        /**
         * 第三方Jar类库的引用。<br/>
         * @throws IOException 
         * */
        public static void findClassName(List<Class<?>> clazzList, String pkgName, URL url, boolean isRecursive, Class<? extends Annotation> annotation) throws IOException {
            JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
            JarFile jarFile = jarURLConnection.getJarFile();
            System.out.println("jarFile:" + jarFile.getName());
            Enumeration<JarEntry> jarEntries = jarFile.entries();
            while (jarEntries.hasMoreElements()) {
                JarEntry jarEntry = jarEntries.nextElement();
                String jarEntryName = jarEntry.getName(); // 类似:sun/security/internal/interfaces/TlsMasterSecret.class
                String clazzName = jarEntryName.replace("/", ".");
                int endIndex = clazzName.lastIndexOf(".");
                String prefix = null;
                if (endIndex > 0) {
                    String prefix_name = clazzName.substring(0, endIndex);
                    endIndex = prefix_name.lastIndexOf(".");
                    if(endIndex > 0){
                        prefix = prefix_name.substring(0, endIndex);
                    }
                }
                if (prefix != null && jarEntryName.endsWith(".class")) {
    //                System.out.println("prefix:" + prefix +" pkgName:" + pkgName);
                    if(prefix.equals(pkgName)){
                        System.out.println("jar entryName:" + jarEntryName);
                        addClassName(clazzList, clazzName, annotation);
                    } else if(isRecursive && prefix.startsWith(pkgName)){
                        // 遍历子包名:子类
                        System.out.println("jar entryName:" + jarEntryName +" isRecursive:" + isRecursive);
                        addClassName(clazzList, clazzName, annotation);
                    }
                }
            }
        }
        
        private static File[] filterClassFiles(String pkgPath) {
            if(pkgPath == null){
                return null;
            }
            // 接收 .class 文件 或 类文件夹
            return new File(pkgPath).listFiles(new FileFilter() {
                @Override
                public boolean accept(File file) {
                    return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory();
                }
            });
        }
        
        private static String getClassName(String pkgName, String fileName) {
            int endIndex = fileName.lastIndexOf(".");
            String clazz = null;
            if (endIndex >= 0) {
                clazz = fileName.substring(0, endIndex);
            }
            String clazzName = null;
            if (clazz != null) {
                clazzName = pkgName + "." + clazz;
            }
            return clazzName;
        }
        
        private static void addClassName(List<Class<?>> clazzList, String clazzName, Class<? extends Annotation> annotation) {
            if (clazzList != null && clazzName != null) {
                Class<?> clazz = null;
                try {
                    clazz = Class.forName(clazzName);
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
    //            System.out.println("isAnnotation=" + clazz.isAnnotation() +" author:" + clazz.isAnnotationPresent(author.class));
                
                if (clazz != null) {
                    if(annotation == null){
                        clazzList.add(clazz);
                        System.out.println("add:" + clazz);
                    } else if (clazz.isAnnotationPresent(annotation)){
                        clazzList.add(clazz);
                        System.out.println("add annotation:" + clazz);
                    }
                }
            }
        }
    }
  • 相关阅读:
    信号的阻塞
    善用布尔值
    多线程
    手机号码合理性的判断
    P(n,x)实现
    兄弟分钱、海盗分赃
    简单四则运算的实现
    模板技术
    合并字符串
    交换机和路由器比较
  • 原文地址:https://www.cnblogs.com/softidea/p/5440753.html
Copyright © 2011-2022 走看看