Let's say a java codebase has a package called "com.example".
At runtime, we can get this Package by calling
Package p = Package.getPackage( "com.example" ); //(returns null)
or even get a list of all packages by calling
Packages[] ps = Package.getPackages();
The problem is - if the ClassLoader has not yet loaded any class from the package, it won't be available to these function calls. We can force it to load the package by force-loading one of the classes in the package first, like this:
this.getClass().getClassLoader().loadClass( "com.example.SomeClass" );
Package p = Package.getPackage( "com.example" ); //(returns non-null)
However, this is hacky and requires knowing ahead of time the name of some class that belongs to the package.
So the question is - is there any way to get an instance of Package by name, regardless of whether or not the ClassLoader has done anything? Are my assumptions about how classloading/packages seem to work in this situation accurate?
I assume you need this because you need to inspect its annotations. Otherwise you wouldn't be interested in having a Package reference which only operations are all around accessing annotations. This leads to the assumtion that you also have a package-info.java defined there with some annotations.
If you check java.lang.Package
you'll see that the getPackageInfo
just loads the package-info class as an ordinary class.
I had the same problem and came up with this solution.
public static Package getPackage(String packageName) throws ClassNotFoundException {
Class.forName(packageName+".package-info"); // makes sure package info exist and that the class loader already knows about the package
return Package.getPackage(packageName);
}
Alternatively you could use the class root directory as a starting point and walk through all *.class files and sub directories. This would only work if you know where all your .class files will reside beforehand.
The cause of all this is that Java has dynamic classloading, so classes can be loaded at runtime from locations not known at compile time or even at startup time. Therefore the concept of a package is just a namespace for loaded classes, not a directory which you can use to look them up.
I'm afraid that your assumptions are not valid. Classloaders do package book-keeping as they load classes.
You can pass a wildcard to ClassLoader.getResources
and force it to pick up the classes in a package, which will in turn do the work.
You can make your own ClassLoader that calls definePackage
, but that won't help you with the usual vanilla classloaders in use.