Java Reflection - 获取软件包列表

2022-09-03 13:34:02

我正在构建一个具有许多不同包的Java应用程序。我希望能够以编程方式分辨出应用中存在哪些以特定预修复程序开头的程序包。有没有用Java反射API来做到这一点?我没有看到与反射 api 相关的类似内容。

例:

com.app.controls.text
com.app.controls.picker
com.app.controls.date
etc

我想通过了解前缀“com.app.controls”并了解将来可能会集成新包来枚举所有这些内容。

谢谢!


答案 1

您可以使用 Package.getPackages() 执行此操作,它返回当前类装入器已知的所有包的数组。您必须手动遍历数组,并使用 getName() 找到具有适当前缀的数组。

下面是一个简单示例:

public List<String> findPackageNamesStartingWith(String prefix) {
    return Package.getPackages().stream()
        .map(Package::getName)
        .filter(n -> n.startsWith(prefix))
        .collect(toList());
}

请注意,此技术将仅返回在当前类装入器中定义的包。如果您需要来自其他类装入器的包,则有一些选项:

  1. 安排一些事情,以便你的程序可以从该类装入器内部运行上述代码。这需要一个特定的组织来构建你的代码库,这可能是可行的,也可能是不可行的。

  2. 使用反射在适当的类装入器上调用(通常受保护的)方法 getPackages()。如果程序在安全管理器下运行,则此操作不起作用。


答案 2

根据 Sean 的回答,并使用反射来获取包列表 - 可能忽略空包:

/**
 * Finds all package names starting with prefix
 * @return Set of package names
 */
public Set<String> findAllPackagesStartingWith(String prefix) {
    List<ClassLoader> classLoadersList = new LinkedList<ClassLoader>();
    classLoadersList.add(ClasspathHelper.contextClassLoader());
    classLoadersList.add(ClasspathHelper.staticClassLoader());
    Reflections reflections = new Reflections(new ConfigurationBuilder()
            .setScanners(new SubTypesScanner(false), new ResourcesScanner())
            .setUrls(ClasspathHelper.forClassLoader(classLoadersList.toArray(new ClassLoader[0])))
            .filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix("my.base.package"))));
    Set<Class<? extends Object>> classes = reflections.getSubTypesOf(Object.class);

    Set<String> packageNameSet = new TreeSet<String>();
    for (Class classInstance : classes) {
        String packageName = classInstance.getPackage().getName();
        if (packageName.startsWith(prefix)) {
            packageNameSet.add(packageName);
        }
    }
    return packageNameSet;
}