Is there a way to force a classloader to load a pa

2020-03-09 18:24发布

问题:

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?

回答1:

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);
}


回答2:

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.



回答3:

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.