提问人:Kodigas 提问时间:11/11/2023 最后编辑:Kodigas 更新时间:11/22/2023 访问量:102
如何以最简洁的方式从包中检索所有类?
How do I retrieve all classes from a package in the neatest way possible?
问:
首先,我想说的是,我读了这篇 StackOverflow 帖子
我目前的理解是,如果你想从一个包(和子包)中获取所有类,而不写大量的代码行,你基本上会被 API 所困。以下是一些选项:Reflections
选项 1.
private static Set<Class<?>> getClassesFromPackage(String packageName) {
Reflections reflections = new Reflections(packageName, new SubTypesScanner(false));
return new HashSet<>(reflections.getSubTypesOf(Object.class));
}
非最佳:已弃用,因此您会收到警告SubTypesScanner
选项 2.
private static Set<Class<?>> getClassesFromPackage(String packageName) {
Reflections reflections = new Reflections(packageName, Scanners.SubTypes.filterResultsBy(s -> true));
return new HashSet<>(reflections.getSubTypesOf(Object.class));
}
不是最佳的:是笨拙的自动对焦,所以你要么得到不容易阅读的代码,要么你必须提供一些元评论Scanners.SubTypes.filterResultsBy(s -> true)
private static Set<Class<?>> getClassesFromPackage(String packageName) {
Reflections reflections = new Reflections(packageName, getStuffThatMakesItWork());
return new HashSet<>(reflections.getSubTypesOf(Object.class));
}
private static Scanners getStuffThatMakesItWork() {
return Scanners.SubTypes.filterResultsBy(s -> true);
}
如果我能写这个,那岂不是很桃色
private static Set<Class<?>> getClassesFromPackage(String packageName) {
Reflections reflections = new Reflections(packageName);
return new HashSet<>(reflections.getSubTypesOf(Object.class));
}
它的可读性要高得多,但遗憾的是它不起作用(返回的集合将包含零项)
扫描包类的最佳方法是什么?
标准:
- 代码应尽可能短。
- 代码应该是可读的(随机的人在查看它时不应该得到任何 WTF 时刻)
- 您不应收到警告
你的解决方案本质上应该实现这个接口(你可能没有在你的答案中明确地这样做):
public interface PackageScanner {
Set<Class<?>> getClassesFromPackage(String packageName);
}
我还没有提到的一件事是,自 2021 年以来,整个库都没有维护过,因此依赖它可能不是一个可靠的长期解决方案。有没有至少同样好的替代品?Reflections
更新:我试图实现 Reilas 的建议,但它导致了一个非常尴尬的代码Class.forName()
// here I reveal that all along I actually wanted to scan for all entities and DTOs
private static void scanForEntitiesAndDtos() {
File sourceRoot = new File("");
entitiesAndDtos.addAll(
Arrays.stream(Objects.requireNonNull(sourceRoot.listFiles()))
.map(clazz -> {
try {
return Class.forName(clazz.getPath());
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
})
.filter(BasicDataGeneratorTest::isEntityOrDto)
.collect(Collectors.toSet())
);
}
private static boolean isEntityOrDto(Class<?> clazz) {
return isEntity(clazz) || isDto(clazz);
}
private static boolean isEntity(Class<?> clazz) {
return clazz.getAnnotation(Entity.class) != null;
}
private static boolean isDto(Class<?> clazz) {
return clazz.getSimpleName().endsWith("Dto");
}
此外,它不起作用,当涉及到 .我尝试过的事情:Objects.requireNotNull()
new File("")
new File("com.example.projectname")
new File("com/example/projectname")
new File("src.main.java.com.example.projectname")
new File("src/main/java/com/example/projectname")
我想这是因为不扫描子目录(谁知道呢,该方法的文档对此保持沉默),但是如果您从 返回的字符串中创建 s,则过滤它们,然后将它们转换为类使用 ,它会变得更加笨拙(假设它都可以工作)listFiles()
File
file.list()
File::isFile
Class.forName(file.getPath())
答:
您声称已经阅读的问题已经有一个答案,其中提到了 ClassGraph,这是一个类似于 Reflections 的库,但很好。
try (ScanResult scanResults = new ClassGraph().acceptPackages(packageName)
.enableClassInfo().scan()) {
Set<Class<?>> entitiesAndDtos = scanResults
.getAllClasses().stream()
.filter(BasicDataGeneratorTest::isEntityOrDto)
.map(ClassInfo::loadClass)
.collect(Collectors.toSet();
}
Jandex 也是一个不错的选择。
评论
Entity