I am building a Java app that has a number of different packages. I want to be able to tell programmatically which packages exist in the app that start with a specific pre-fix. Is there anyway to do this with the Java reflection APIs? I didn't see anything like this related to the reflection apis.
Example:
com.app.controls.text
com.app.controls.picker
com.app.controls.date
etc
I want to enumerate all of these by knowing the prefix "com.app.controls" and understanding that a new package might get integrated in the future.
Thanks!
You can do this by using Package.getPackages(), which returns an array of all packages known to the current class loader. You'll have to manually loop through the array and find the ones with the appropriate prefix using getName().
Here's a quick example:
public List<String> findPackageNamesStartingWith(String prefix) {
return Package.getPackages().stream()
.map(Package::getName)
.filter(n -> n.startsWith(prefix))
.collect(toList());
}
Note that this technique will only return the packages defined in the current class loader. If you need the packages from a different class loader, there are some options:
Arrange things so that your program can run the above code from inside that class loader. This requires a certain organisation to your code base, which may or may not be feasible.
Use reflection to call the (normally protected) method getPackages() on the appropriate class loader. This won't work if the program is running under a security manager.
Based on Sean's answer and using reflection to get a list of packages - possibly ignoring empty ones:
/**
* 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;
}