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

Reply via email to