There are intentional differences between compile-time and run-time for
the --patch-module option. The main one is that the compiler allows
module-info.java on the patch path. If my memory is correct then this is
a forced move to allow for javadoc comments and SOURCE annotations that
are not in the module-info.class.
The "patching an automatic module" scenario is unusual but should work
as the features compose. As you note, the --patch-module can be used to
augment the module content to add "new packages". As automatic modules
export (and open) all packages then the expectation should be that the
"new packages" are also exported. So needing --add-exports at compile
time is a surprise.
cc'ing compiler-dev as Alex or Jan may have more to say on this.
(As a general point, it's a bit sad to be forced into helping target.jar
in 2026)
-Alan
On 12/08/2026 13:21, Rafael Winterhalter wrote:
Hi,
I ran into a compile/run difference with --patch-module and wanted to check
which behaviour is intended before filing anything.
The goal is to give a plain jar a stable automatic module name that does
not depend on its file name, without modifying the jar. So there are two
jars:
- target.jar — the real library. No module-info.class, no
Automatic-Module-Name, so no module identity at all.
- alias.jar — synthesized, empty apart from a manifest with
Automatic-Module-Name: foo. It contains no packages. Its only job is to put
the name foo into the module graph, since --patch-module can augment an
existing module but cannot create one.
Then alias.jar goes on the module path and the real content arrives as:
--patch-module foo=target.jar
javac adds the patched packages to foo but does not export them:
error: package p is not visible
(package p is declared in module foo, which does not export it)
Adding --add-exports foo/p=consumer fixes it. The java launcher needs no
such flag — there the patched packages are exported, and the same program
runs fine.
The cause looks like two different models. Modules.setupAutomaticModule
materialises msym.exports by listing msym.classLocation only, so packages
arriving via PATCH_MODULE_PATH never enter the list. At runtime
Module.isExported derives the answer for automatic modules from
descriptor.packages(), and ModulePatcher keeps the AUTOMATIC modifier while
enlarging that set, so the patched packages come out exported.
Which side is intended? I couldn't find it documented either way, and
JDK-8210151 looks like the same kind of divergence pointing in the other
direction. Happy to file a bug if the javac side is the one that's wrong.
Thanks, Rafael