I have a named module that uses some --add-exports
at compile time.
How can I imply this directive without specifying it manually in the run command line ?
javac --add-exports java.base/sun.security.x509=mymodule --module-source-path src -d bin --module mymodule
jar -c --file=mymodule.jar --main-class=mymodule.Main -C bin/mymodule
java --module-path . --module mymodule/mymodule.Main
causes :
cannot access class sun.security.x509.AlgorithmId (in module java.base) because module java.base does not export sun.security.x509 to module mymodule
--add-exports
is specified for the run, it runs fine
java --add-exports java.base/sun.security.x509=mymodule --module-path . --module mymodule/mymodule.Main
Add-Exports
is specified in the MANIFEST.MF and the jar is run as an un-named module, it should run fine java -jar mymodule.jar
but does not. This used to work in JRE 11 and now fails in JRE 17 (latest at the moment of writing)cannot access class sun.security.x509.AlgorithmId (in module java.base) because module java.base does not export sun.security.x509 to unnamed module @0x53bd815b
http://openjdk.java.net/jeps/261 states :
A module/package pair in the value of an Add-Exports attribute has the same meaning as the command-line option --add-exports module/package=ALL-UNNAMED
How can I specify that the export is not to ALL-UNNAMED
but mymodule
instead ? How to actually make it work ?
If mymodule is not the main class but a library used deeper, then I must specify all exports for all possible modules that I may sometimes use directly from the command line ?
It seems that at this stage (JRE 17), this is not possible.
The exports are performed only in 2 cases :
when starting with the command line parameter --add-exports
(obviously)
when starting the program with the -jar
option, it checks the MANIFEST.MF
for the Add-Exports
directive. This is the only case so far where the manifest is checked.
This means that starting with java -cp my.jar my.Main
will not check the manifest of the jar file.
This means that starting with java --module my.module
will not check the manifest either.
This is rather sad because it spoils the java module system. If one of your dependent module needs those exports, you need to set them at the command line parameter and you need to know it in advance. This is usually the case with those sun.*
classes that no one is supposed to use but that everyone uses anyways. @Oracle : So either expose it publicly (and thus no need to add-exports) or remove it completely from the JRE if we are unable to use it anyways...
Load the dependent modules dynamically at runtime yourself using a URLClassLoader
and do the exports yourself (ugly).
String exports = jarFile.getManifest().getMainAttributes().getValue("Add-Exports");
if( exports != null )
{
for (String moduleAndPackage : exports.split(" "))
{
String[] s = moduleAndPackage.trim().split("/");
if (s.length != 2) continue;
jdk.internal.module.Modules.addExports(ModuleLayer.boot().findModule(s[0]).orElseThrow(), s[1]);
}
}
And guess what, in order to do this, you need to use the restricted java.base/jdk.internal.module
package... which you can now export once for all using the manifest option if your program can be launched with -jar
.
This can thus prevent to add all the exports (that you may not be aware of) manually in the command line.