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 classautomod.Foo
.automod.Foo
is packaged intoautomod.jar
and put on themodule-path
. module-info for moduleA hasrequires automod;
clause. This works fine, as expected.automod.Foo
calls a method onnonmodular.Junk
class.nonmodular.Junk
is packaged intononmodular.jar
and put onclasspath
. This works fine, as expected.nonmodular.Junk
calls a method on moduleX'smodX.X
.modX.X
is packaged intomoduleX.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 haveexports 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.
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 themodule-info
file, finds therequires
directives, and then searches the modulepath for those required modules. It does this transitively. Some modules also declare one or moreuses
directives on a service. Any modules on the modulepath thatprovides
any of those services will also be loaded, regardless of if any modulerequires
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:
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 yourmoduleX
module is loaded. This can be forced by using--add-modules
:Note you can also limit the modules via
--limit-modules
.