All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.neko233.config233.utils.PackageScannerForConfig233 Maven / Gradle / Ivy

The newest version!
package com.neko233.config233.utils;


import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;

public final class PackageScannerForConfig233 {
    private PackageScannerForConfig233() {
    }

    public static Set> scanClass(String packageName, boolean recursive, Class parentClass) {
        if (parentClass == null) {
            return Collections.emptySet();
        } else {
            parentClass.getClass();
            return scanClass(packageName, recursive, parentClass::isAssignableFrom);
        }
    }

    public static Set> scanClassRecursive(String packageName, Class parentClass) {
        return scanClass(packageName, true, parentClass);
    }

    public static Set> scanClass(String packageName, boolean recursive) {
        return scanClass(packageName, recursive, (clazz) -> {
            return true;
        });
    }

    public static Set> scanClass(Class appClass) {
        return scanClass(appClass.getPackage().getName(), true, (clazz) -> {
            return true;
        });
    }

    public static Set> scanClass(Class appClass, boolean recursive, ClassFilterApi filter) {
        return scanClass(appClass.getPackage().getName(), recursive, filter);
    }

    /**
     * 扫描包中的类
     *
     * @param packageName 包名
     * @param recursive   是否递归扫描子目录
     * @param filter      过滤器
     * @return 类集合
     */
    public static Set> scanClass(String packageName, boolean recursive, ClassFilterApi filter) {
        Set> resultSet = new HashSet<>();

        if (packageName == null || packageName.isEmpty()) {
            return resultSet;
        }
        String packagePath = packageName.replace('.', '/');
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        try {
            Enumeration urls = classLoader.getResources(packagePath);
            while (urls.hasMoreElements()) {
                URL url = urls.nextElement();
                String protocol = url.getProtocol();
                if ("file".equalsIgnoreCase(protocol)) {
                    // 扫描文件目录中的类
                    String filePath = URLDecoder.decode(url.getFile(), StandardCharsets.UTF_8.toString());
                    scanClassFromDir(resultSet, filePath, packageName, recursive, filter);
                } else if ("jar".equalsIgnoreCase(protocol)) {
                    // 扫描 JAR 文件中的类
                    scanClassFromJar(resultSet, url, packageName, recursive, filter);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return resultSet;
    }

    /**
     * 从文件目录中扫描类
     *
     * @param resultSet   结果集
     * @param filePath    文件路径
     * @param packageName 包名
     * @param recursive   是否递归扫描子目录
     * @param filter      过滤器
     */
    private static void scanClassFromDir(Set> resultSet, String filePath, String packageName, boolean recursive, ClassFilterApi filter) {
        File dir = new File(filePath);
        if (!dir.exists() || !dir.isDirectory()) {
            return;
        }

        File[] files = dir.listFiles(file -> file.isDirectory() || file.getName().endsWith(".class"));
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory() && recursive) {
                    // 递归扫描子目录
                    scanClassFromDir(resultSet, file.getAbsolutePath(), packageName + "." + file.getName(), recursive, filter);
                } else if (file.getName().endsWith(".class")) {
                    // 加载类
                    String className = packageName + '.' + file.getName().substring(0, file.getName().length() - 6);
                    addClass(resultSet, className, filter);
                }
            }
        }
    }

    /**
     * 从 JAR 文件中扫描类
     *
     * @param resultSet   结果集
     * @param url         JAR 文件 URL
     * @param packageName 包名
     * @param recursive   是否递归扫描子目录
     * @param filter      过滤器
     */
    private static void scanClassFromJar(Set> resultSet, URL url, String packageName, boolean recursive, ClassFilterApi filter) {
        try {
            // 打开 Jar 文件连接
            JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
            JarFile jarFile = jarURLConnection.getJarFile();
            Enumeration entries = jarFile.entries();

            while (entries.hasMoreElements()) {
                JarEntry entry = entries.nextElement();
                String name = entry.getName();
                if (name.startsWith(packageName.replace('.', '/'))) {
                    // 匹配包名
                    int idx = name.lastIndexOf('/');
                    if ((idx != -1 || recursive) && name.endsWith(".class") && !entry.isDirectory()) {
                        // 匹配类名-去掉 .class 后缀
                        String className = name.substring(0, name.length() - 6).replace('/', '.');
                        addClass(resultSet, className, filter);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 添加类
     *
     * @param resultSet 结果集
     * @param className 类名称
     * @param filter    过滤器
     */
    private static void addClass(Set> resultSet, String className, ClassFilterApi filter) {
        try {
            Class clazz = Class.forName(className);
            if (filter == null || filter.isNeed(clazz)) {
                resultSet.add(clazz);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }


    @FunctionalInterface
    public interface ClassFilterApi {
        boolean isNeed(Class var1);

        default boolean isNotNeed(Class clazz) {
            return !this.isNeed(clazz);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy