我正在构建一个包含许多不同包的Java应用程序。我希望能够以编程方式告诉应用程序中存在哪些软件包以特定的预修复程序开头。无论如何使用Java反射API执行此操作?我没有看到与反射apis相关的任何事情。
示例:
com.app.controls.text
com.app.controls.picker
com.app.controls.date
etc
我希望通过知道前缀“com.app.controls”来枚举所有这些,并了解将来可能会集成新的包。
谢谢!
答案 0 :(得分:17)
您可以使用Package.getPackages()执行此操作,它返回当前类加载器已知的所有包的数组。您必须手动遍历数组并使用getName()找到具有相应前缀的数组。
这是一个简单的例子:
public List<String> findPackageNamesStartingWith(String prefix) {
return Package.getPackages().stream()
.map(Package::getName)
.filter(n -> n.startsWith(prefix))
.collect(toList());
}
请注意,此技术仅返回当前类加载器中定义的包。如果您需要来自不同类加载器的包,则有一些选项:
安排事情,以便您的程序可以从该类加载器内部运行上述代码。这需要某个组织到您的代码库,这可能是也可能是不可行的。
使用反射在相应的类加载器上调用(通常受保护的)方法getPackages()。如果程序在安全管理器下运行,则无效。
答案 1 :(得分:-1)
基于Sean's answer并使用反射来获取包列表 - 可能忽略空包:
/**
* 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;
}