问题 Java反射 - 获取包列表


我正在构建一个包含许多不同包的Java应用程序。我希望能够以编程方式告诉应用程序中存在哪些软件包以特定的预修复程序开头。无论如何使用Java反射API执行此操作?我没有看到与反射apis相关的任何内容。

例:

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

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

谢谢!


6169
2017-12-19 02:19


起源



答案:


你可以通过使用来做到这一点 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() 在适当的类加载器上。如果程序在安全管理器下运行,这将不起作用。


17
2017-12-19 02:25



不幸的是,当前的类加载器不知道包。还有其他可能的方法吗? - Derek Gebhard
可能不是,除了明确列出它们之外。 - Louis Wasserman
@DerekGebhard:想到了两种可能性。我已将它们添加到答案中。 - Sean Reilly


答案:


你可以通过使用来做到这一点 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() 在适当的类加载器上。如果程序在安全管理器下运行,这将不起作用。


17
2017-12-19 02:25



不幸的是,当前的类加载器不知道包。还有其他可能的方法吗? - Derek Gebhard
可能不是,除了明确列出它们之外。 - Louis Wasserman
@DerekGebhard:想到了两种可能性。我已将它们添加到答案中。 - Sean Reilly


基于 肖恩的回答 并使用反射来获取包列表 - 可能忽略空包:

/**
 * 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;
}

-1
2018-01-27 12:41



不适用于子包装 - cyril
我的本机库中不存在大多数这些类。你在使用第三方吗? - Lord Farquaad