如何以最简洁的方式从包中检索所有类?

问题描述 投票:0回答:1

首先,我想说我读过这篇 StackOverflow 帖子

我目前的理解是,如果您想从包(和子包!)中获取所有类而不编写大量代码行,那么您基本上只能使用

Reflections
API。以下是一些选项:

选项 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)
是笨拙的AF,所以你要么得到不易阅读的代码,要么你必须提供一些元注释

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

它的可读性要高得多,但遗憾的是它不起作用(返回的集合将包含零个项目)

扫描包类的最佳方法是什么?

标准:

  1. 代码应尽可能短。
  2. 代码应该是可读的(随机的人在查看它时不应该有任何WTF时刻)
  3. 您不应该收到警告

您的解决方案本质上应该实现此接口(您可能不会在答案中明确执行):

public interface PackageScanner {
    Set<Class<?>> getClassesFromPackage(String packageName);
}

我还没有提到的一件事是,自 2021 年以来,整个

Reflections
库就不再被维护,因此依赖它可能不是一个可靠的长期解决方案。有没有至少同样好的替代方案?

UPD:我尝试实现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()

时我得到了NPE。我尝试过的事情:

  • 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")
    
    
我猜这是因为

listFiles()

 不扫描子目录(谁知道,该方法的文档对此保持沉默),但是如果您从 
File
 返回的字符串创建 
file.list()
,则通过 
File::isFile
 过滤它们,然后使用 
Class.forName(file.getPath())
 将它们转换为类,它变得更加笨拙(假设它都能工作)

java reflection
1个回答
0
投票
您声称已经阅读过的问题已经有

一个答案,其中提到了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也是一个不错的选择。

© www.soinside.com 2019 - 2024. All rights reserved.