扫描一个类所在目录下的所有类的类名[包括Jar和非jar]

/**
     * 扫描一个类所在目录下的所有类的类名
     *
     * @param clazz  要扫描的基础类
     * @param filter 过滤器 为空的时候不过滤
     * @return 一个全路径类名的List
     */
     public static List<String> scanAllClass(Class clazz, int back, Function<String, Boolean> filter) {
        List<String> classes = new LinkedList<>();
        try {
            URL url = clazz.getResource("");
            StringBuilder sb = new StringBuilder(URLDecoder.decode(url.getPath(), "UTF-8"));
            //取父目录 0 或者null的时候是本级不用变  但是1的时候要+1 是因为要把最后一个/也去掉
            int level = back == 0 ? 0 : 1 + back;
            for (int i = 0; i < level; i++) {
                int index = sb.lastIndexOf("/");
                sb = sb.delete(index, sb.length());
            }
            //补回最后一个/
            if (level > 0) {
                sb.append("/");
            }
            String decode = sb.toString();
            System.out.println(decode);
            //判断是jar包还是文件夹
            String[] split = decode.split("\\.jar!/");

            if (split.length > 1) {

                //打开jar文件
                JarURLConnection connection = (JarURLConnection) url.openConnection();
                JarFile jarFile = connection.getJarFile();
                Enumeration<JarEntry> jarEntries = jarFile.entries();
                //遍历jar包下的所有文件
                while (jarEntries.hasMoreElements()) {
                    JarEntry jarEntry = jarEntries.nextElement();
                    String jarEntryName = jarEntry.getName();

                    //查找出类
                    if (jarEntryName.startsWith(split[split.length - 1]) && jarEntryName.endsWith(".class")) {
                        String className = jarEntryName.replace("/", ".");
                        //执行过滤器
                        if (filter != null && !filter.apply(className)) {
                            continue;
                        }
                        classes.add(className.replaceAll(".class$", ""));
                    }
                }
            } else {
                //todo mac 下测试效果
                //计算出从包名开始往下的路径
                //linux 下和windows下有所区别  windows下的decode 前面会加上一个 / 所以分隔符是\的时候 subNum要+1
                String separator = System.getProperty("file.separator");
                int subNum = "\\".equals(separator) ? 2 : 1;
                int bathLength = decode.length() - subNum - clazz.getPackage().getName().length();

                //BFS
                Queue<File> queue = new LinkedList<>();
                File file = new File(decode);
                queue.add(file);
                while (!queue.isEmpty()) {
                    for (int i = 0; i < queue.size(); i++) {
                        File poll = queue.poll();
                        String absolutePath = poll.getCanonicalPath();
                        if (absolutePath.endsWith(".class")) {
                            String substring = absolutePath.substring(bathLength);
                            String className = substring.replace(separator, ".");
                            //执行过滤器
                            if (filter != null && !filter.apply(className)) {
                                continue;
                            }
                            //将分割符切换成.
                            classes.add(className.replaceAll(".class$", ""));
                        } else {
                            if (poll.canRead() && poll.isDirectory()) {
                                File[] files = poll.listFiles();
                                //如果有子文件 入队
                                for (File f : files) {
                                    queue.add(f);
                                }
                            }
                        }
                    }

                }
            }
        } catch (Exception e) {

            throw new RuntimeException(e);
        }
        return classes;
    }


    public static void main(String[] args) {

        System.out.println(scanAllClass(DataMemoryApplication.class, null));

        System.out.println(scanAllClass(org.springframework.cache.Cache.class, null));
        //过滤内部类
        System.out.println(scanAllClass(org.springframework.cache.Cache.class, s -> !s.contains("$")));
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值