A build directory `mods` contains two artifacts:
- `legacy.jar` — a plain JAR with no `module-info.class` and no `Automatic-Module-Name` in its manifest, containing the package `com.legacy`.
- `com.app` — an explicit module compiled from:
```java
module com.app {
requires legacy;
}
```
whose `com.app.Main` calls `com.legacy.Legacy.hi()`.
Both `javac --module-path mods ...` and `java --module-path mods --module com.app/com.app.Main` succeed; the application prints `legacy`. The team now wants a self-contained runtime image and runs:
```
jlink --module-path mods --add-modules com.app --output image
```
What is the result?
A. jlink fails because legacy was not named as a root; adding `--add-modules com.app,legacy` produces the image.
Misdiagnoses the error as a resolution-root problem. Naming legacy explicitly does not help — jlink rejects the KIND of module (automatic), not its absence from the root set, so it just reports the same error sooner.
B. The image is created; jlink copies legacy.jar into image/lib and the packaged application runs normally.
Assumes jlink is a packager that bundles whatever is on the module path. jlink links MODULES, and only explicit or JDK modules qualify; an automatic module has no descriptor to close over, so linking fails.
C. The image is created, but launching it fails because the automatic module was linked without its exports.
Pushes the failure to run time. There is no image to launch — jlink exits non-zero and produces no output directory, because it cannot resolve the automatic module's "everything" requires/exports into a fixed image.
D. jlink fails with `Error: automatic module cannot be used with jlink: legacy`.Correct answer
A plain JAR on the module path is an automatic module; javac and java accept it, but jlink needs a closed, statically-known module graph and an automatic module has no descriptor, so resolving root com.app pulls in `requires legacy` and jlink rejects it transitively.
Explanation
A plain JAR dropped on the module path becomes an *automatic module*: javac and java both accept it, deriving the name `legacy` from the file name and treating it as if it exported everything and read everything. jlink is the one tool in the chain that refuses. jlink must compute a closed, statically-known module graph in order to link it into an image, and an automatic module has no descriptor to close over — its `requires` set is "everything" and its `exports` set is "all packages", neither of which can be resolved into a fixed image. So jlink rejects it outright, and it rejects it *transitively*: the command above never even names `legacy`, but resolving the root `com.app` pulls `requires legacy` in, and the link fails.
Why the others are wrong:
`The image is created; jlink copies legacy.jar into image/lib...` assumes jlink is a packager that bundles whatever is on the module path. It is not — it links *modules*, and only explicit or JDK modules qualify. (This is also why jlink cannot consume a plain class path at all.)
`The image is created, but launching it fails...` pushes the failure to run time. There is no image to launch: jlink exits non-zero and produces no output directory.
`jlink fails because legacy was not named as a root...` misdiagnoses the error as a resolution-root problem. Naming legacy explicitly does not help — it is the *kind* of module that is rejected, not its absence from the root set, so adding it as a root just reports the same automatic-module error sooner.
Exam tip: automatic modules are a *migration* device, and jlink is the wall they hit. To ship a jlink image you must first give every dependency a real descriptor — write `module-info.java` for it (`jdeps --generate-module-info` will draft one). Remember the asymmetry: javac ✅, java ✅, jlink ❌. The reverse trap is a question that claims automatic modules cannot be used at all — they can, everywhere except linking.