Task: load any application class using a custom class loader (CustomClassLoader
) from another module (the modules are NOT linked through module-info.java
).
Modules (declared via module-info.java
):
manual.fewmodules.separately.nodeps.loading
:Main
- a class containing themain
method, where an instance of theCustomClassLoader
class is created, theCat
class is loaded using it, creating an instance of the classCat
and calling theCat::talk
method;CustomClassLoader
- a class that is an implementation of a custom class loader;
manual.fewmodules.separately.nodeps.loadable
:Cat
- loadable class with thetalk
method, which prints the string "Meow" tostdout
.
Using modulepath
:
java17 -p loading-1.0.jar -m manual.fewmodules.separately.nodeps.loading
Output:
[loading] Main Class Module is module manual.fewmodules.separately.nodeps.loading
[loading] Main Class ClassLoader is jdk.internal.loader.ClassLoaders$AppClassLoader@4554617c
ClassLoader for [loadable] module is jdk.internal.loader.Loader@4a574795
[loadable] Main Class ClassLoader is jdk.internal.loader.Loader@4a574795
[loadable] Cat Class ClassLoader is jdk.internal.loader.Loader@4a574795
[loadable] Main Class Module is module manual.fewmodules.separately.nodeps.loadable
[loadable] Cat Class Module is module manual.fewmodules.separately.nodeps.loadable
Meow
The class modules are as we wanted, but the Cat
class loader turned out to be not CustomClassLoader
as we expected, but some Loader
. The fact is that in the defineModuleWithOneLoader
method, a new Loader
loader is created (the same one that I mentioned in the Java 8: Auto Loading example), the parent of which becomes the passed CustomClassLoader
.
private static ModuleLayer createLayer(Path modulePath, String moduleName) {
/* ... */
return bootLayer.defineModulesWithOneLoader(config, new CustomClassLoader());
}
Indeed, in documentation so and it is written:
public ModuleLayer defineModulesWithOneLoader(Configuration cf, ClassLoader parentLoader)
parentLoader
- The parent class loader for the class loader created by this method; may benull
for the bootstrap class loader.
Thus, we do not have the opportunity to somehow pass our own class loader to the layer; we can only indicate the parent for the newly created one. Moreover, according to the same documentation, class loading will be delegated to the parent only if Loader
does not find the package in which the class is located, here you can come up with different hacks based on this delegation model.
- You can rewrite the code a little and add a hack that will force
Loader
to delegate class loading to a custom class loader: Java 17. Manual Loading (loading and loadable) - hack