Reputation: 1144
I am trying out the various access rules about who can access and what and I saw this statement in The State of the module system document,
The unnamed module reads every other module. Code in any type loaded from the class path will thus be able to access the exported types of all other readable modules, which by default will include all of the named, built-in platform modules.
So, I wrote the following code to test it out with the following structure:
moduleA/modA.A --> automod/automod.Foo --> nonmodular.Junk --> moduleX/modX.X
Basically,
moduleA's modA.A
calls a method on a non-modular class automod.Foo
. automod.Foo
is packaged into automod.jar
and put on the module-path
. module-info for moduleA has requires automod;
clause. This works fine, as expected.
automod.Foo
calls a method on nonmodular.Junk
class. nonmodular.Junk
is packaged into nonmodular.jar
and put on classpath
. This works fine, as expected.
nonmodular.Junk
calls a method on moduleX's modX.X
. modX.X
is packaged into moduleX.jar
.
It is this step that has a problem. It works if I put moduleX.jar on classpath but not if I put moduleX.jar on module-path. (module-info for moduleX does have exports modX;
clause.)
In other words, the following command works:
java --module-path moduleA.jar;automod.jar; -classpath nonmodular.jar;moduleX.jar --module moduleA/modA.A
With the following output:
In modA.A.main() Calling automod.Foo()
In automod.Foo()
In modA.A.main() Calling automod.foo.main()
In automod.Foo.main() Calling nonmodular.Junk()
In automod.Foo.main() Calling nonmodular.Junk.main()
In nonmodular.Junk.main calling new modX.X()
In modX.X()
But the following command doesn't work:
java --module-path moduleA.jar;automod.jar;moduleX.jar -classpath nonmodular.jar; --module moduleA/modA.A
Here is the output:
In modA.A.main() Calling automod.Foo()
In automod.Foo()
In modA.A.main() Calling automod.foo.main()
In automod.Foo.main() Calling nonmodular.Junk()
In automod.Foo.main() Calling nonmodular.Junk.main()
In nonmodular.Junk.main calling new modX.X()
Exception in thread "main" java.lang.NoClassDefFoundError: modX/X
at nonmodular.Junk.main(Junk.java:5)
at automod/automod.Foo.main(Foo.java:10)
at moduleA/modA.A.main(A.java:10)
Caused by: java.lang.ClassNotFoundException: modX.X
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
... 3 more
Any idea why? Any class loaded from the classpath should be able to access any classes exported by a module.
Upvotes: 2
Views: 1360
Reputation: 45746
When you start a Java application with the --module
command, the value you pass is a "root" module. The same is true of modules added via --add-modules
. The module system determines the entire module graph from these root modules. In other words, it reads the module-info
file, finds the requires
directives, and then searches the modulepath for those required modules. It does this transitively. Some modules also declare one or more uses
directives on a service. Any modules on the modulepath that provides
any of those services will also be loaded, regardless of if any module requires
them.
This means if there's a module on the modulepath that isn't required by any loaded module and doesn't provide any services needed by any loaded module then said module won't be loaded. If you're interested in seeing what modules are resolved you can use the following command:
java --show-module-resolution --dry-run -p [MODULEPATH] -m [MODULE]
In your case I can only assume that none of your other modules require modularX
, so when its on the modulepath it doesn't get loaded. However, when its on the classpath things work differently and its found by your non-modular code that's also on the classpath. You can still use the modulepath though, just make sure your moduleX
module is loaded. This can be forced by using --add-modules
:
java -p moduleA.jar;automod.jar;moduleX.jar --add-modules moduleX -cp nonmodular.jar -m moduleA/modA.A
Note you can also limit the modules via --limit-modules
.
Upvotes: 3