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);
}
}
}