[新特性]

cn.hutool.core.lang.ClassScanner
scan(boolean,boolean)
增加忽略加载错误类的扫描方法,同时收集了错误的类名,使用简单逻辑编写了测试方法进行测试.

当前 JavaSourceCompilerTest 的几个类恰好不能正常加载,被正确忽略。
This commit is contained in:
frank.lee 2022-10-28 12:31:48 +08:00
parent ec14f8384a
commit f419507049
2 changed files with 59 additions and 3 deletions

View File

@ -66,6 +66,16 @@ public class ClassScanner implements Serializable {
*/
private final Set<Class<?>> classes = new HashSet<>();
/**
* 忽略loadClass时的错误
*/
private boolean ignoreLoadError = false;
/**
* 获取加载错误的类名列表
*/
private final Set<String> classesOfLoadError = new HashSet<>();
/**
* 扫描指定包路径下所有包含指定注解的类包括其他加载的jar或者类
*
@ -221,6 +231,19 @@ public class ClassScanner implements Serializable {
return scan(false);
}
/**
* 扫描
*
* @param forceScanJavaClassPaths 是否强制扫描其他位于classpath关联jar中的类
* @param ignoreLoadError 是否或略扫描时loadClass的异常
* @return 类集合
*
*/
public Set<Class<?>> scan(boolean forceScanJavaClassPaths,boolean ignoreLoadError){
this.ignoreLoadError = ignoreLoadError;
return scan(forceScanJavaClassPaths);
}
/**
* 扫描包路径下满足class过滤器条件的所有class文件
*
@ -229,6 +252,11 @@ public class ClassScanner implements Serializable {
* @since 5.7.5
*/
public Set<Class<?>> scan(boolean forceScanJavaClassPaths) {
//多次扫描时,清理上次扫描历史
this.classes.clear();
this.classesOfLoadError.clear();
for (URL url : ResourceUtil.getResourceIter(this.packagePath)) {
switch (url.getProtocol()) {
case "file":
@ -267,8 +295,20 @@ public class ClassScanner implements Serializable {
this.classLoader = classLoader;
}
/**
* 忽略加载错误扫描后可以获得之前扫描时加载错误的类名字集合
*/
public Set<String> getClassesOfLoadError(){
return Collections.unmodifiableSet(this.classesOfLoadError);
}
// --------------------------------------------------------------------------------------------------- Private method start
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
/**
* 扫描Java指定的ClassPath路径
*/
@ -341,7 +381,7 @@ public class ClassScanner implements Serializable {
* @param className 类名
* @return 加载的类
*/
private Class<?> loadClass(String className) {
protected Class<?> loadClass(String className) {
ClassLoader loader = this.classLoader;
if (null == loader) {
loader = ClassLoaderUtil.getClassLoader();
@ -353,10 +393,16 @@ public class ClassScanner implements Serializable {
clazz = Class.forName(className, this.initialize, loader);
} catch (NoClassDefFoundError | ClassNotFoundException e) {
// 由于依赖库导致的类无法加载直接跳过此类
classesOfLoadError.add(className);
} catch (UnsupportedClassVersionError e) {
// 版本导致的不兼容的类跳过
} catch (Exception e) {
throw new RuntimeException(e);
classesOfLoadError.add(className);
} catch (Throwable e){
if(!this.ignoreLoadError) {
throw new RuntimeException(e);
}else{
classesOfLoadError.add(className);
}
}
return clazz;
}

View File

@ -32,4 +32,14 @@ public class ClassScanerTest {
final Set<Class<?>> classes = ClassScanner.scanAllPackageBySuper(null, Iterable.class);
Console.log(classes.size());
}
@Test
@Ignore
public void scanAllPackageIgnoreLoadErrorTest(){
ClassScanner classScanner = new ClassScanner(null, null);
final Set<Class<?>> classes = classScanner.scan(false,true);
Console.log(classes.size());
Console.log(classScanner.getClassesOfLoadError());
}
}