我正在构建一个包含许多不同包的 Java 应用程序。我希望能够以编程方式告诉应用程序中存在哪些以特定前缀开头的包。无论如何使用Java反射API来做到这一点?我没有看到与反射api相关的任何东西。
例子:
com.app.controls.text
com.app.controls.picker
com.app.controls.date
etc
我想通过了解前缀“com.app.controls”来列举所有这些,并了解未来可能会集成一个新包。
谢谢!
我正在构建一个包含许多不同包的 Java 应用程序。我希望能够以编程方式告诉应用程序中存在哪些以特定前缀开头的包。无论如何使用Java反射API来做到这一点?我没有看到与反射api相关的任何东西。
例子:
com.app.controls.text
com.app.controls.picker
com.app.controls.date
etc
我想通过了解前缀“com.app.controls”来列举所有这些,并了解未来可能会集成一个新包。
谢谢!
您可以使用Package.getPackages()来做到这一点,它返回当前类加载器已知的所有包的数组。您必须手动遍历数组并使用getName()找到具有适当前缀的数组。
这是一个简单的例子:
public List<String> findPackageNamesStartingWith(String prefix) {
return Package.getPackages().stream()
.map(Package::getName)
.filter(n -> n.startsWith(prefix))
.collect(toList());
}
请注意,此技术将仅返回当前类加载器中定义的包。如果您需要来自不同类加载器的包,有一些选项:
安排一些事情,以便您的程序可以从该类加载器内部运行上述代码。这需要对您的代码库进行特定组织,这可能可行,也可能不可行。
使用反射在适当的类加载器上调用(通常受保护的)方法getPackages() 。如果程序在安全管理器下运行,这将不起作用。
根据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;
}