skip to content

Why can a named module not read the unnamed module, and how does this affect migrating an app to JPMS?

level: seniorimportance: should knowfreq 45%

answer

  1. requires takes a NAME; unnamed module has no name
  2. Named module cannot read unnamed; automatic module can
  3. Classpath leftovers land in the unnamed module -> invisible to named modules
  4. Fix: move the JAR to the module path (named or automatic)
  5. Drives top-down migration via automatic modules

basics

~20 s

The unnamed module has no name, and a module-info file declares dependencies by name (requires X). With no name to write, a named module literally cannot require the unnamed module, so it cannot see any code left on the classpath.

solid answer

~50 s

A named module declares every dependency in its module-info using `requires <module-name>`. The unnamed module — the bucket holding all classpath code — has no name, so there is no token you could put after `requires`. Hence the language rule: a named module cannot read the unnamed module. Practically, when you modularise an application by giving it a module-info but leave some library on the classpath, that library now lives in the unnamed module and your named module suddenly can't see it, producing 'package is not visible' or resolution errors. The fix is to move that dependency onto the module path, where it becomes either a named module (if it has module-info) or an automatic module (if it doesn't) — both of which have names and can be required. This is why migration is usually done top-down, modularising the app while leaning on automatic modules for not-yet-modular dependencies.

go deeper

for a junior

Knows that classpath code is the unnamed module and that a fully modular app may not see it.

for a middle

Can state the rule and that the unnamed module has no name, and knows code on the classpath lands there.

for a senior

Explains the rule as a consequence of name-based requires plus the reliable-configuration goal, recognises the resolution error, and fixes it by moving the dependency to the module path.

for a principal

Frames top-down migration strategy, weighs automatic modules as a transitional bridge, and reasons about the configuration-soundness rationale behind denying named modules classpath access.

## What 'reads' means in JPMS In module-system vocabulary, module A **reads** module B when A is allowed to access B's exported types. Readability is established by dependency declarations: in A's `module-info.java` you write `requires B`. At resolution time the runtime builds a **readability graph** from these declarations; if A doesn't read B, code in A simply cannot reference B's classes, even public ones. ## The unnamed module, recapped Everything loaded from the **classpath** is collected into a single special module per class loader called the **unnamed module**. It has two relevant properties: it **reads every other module** (so classpath code can use any modular library), and — critically — it **has no name**. The lack of a name is by design: the classpath is an unordered free-for-all, so there is no meaningful single name to give it. ## Why the rule exists (it falls out of the design) A `module-info` can only express dependencies *by name*: the syntax is literally `requires <module-name>;`. Since the unnamed module has no name, **there is no name to write** — you cannot express a dependency on it. So a named module structurally cannot read the unnamed module. It isn't an arbitrary prohibition; it is a direct consequence of (a) named modules declaring dependencies by name and (b) the unnamed module having no name. There is also a soundness motive: the whole point of a named module is *reliable configuration* — its dependencies are explicit and validated. If a named module could implicitly pull in the entire anonymous classpath, you'd reintroduce exactly the 'anything can see anything' fragility that modules were meant to remove. The rule keeps named modules honest. Note the contrast with **automatic modules**, which *can* read the unnamed module. Automatic modules exist precisely to bridge to legacy code, so they are granted that implicit access; named modules are not. ## The migration impact Suppose your app code becomes a named module `com.acme.app` with a `module-info`, but you keep depending on `oldlib.jar` and leave it on the classpath. Now: - `oldlib.jar` is in the **unnamed module**. - `com.acme.app` is a **named module** and *cannot read the unnamed module*. - Result: code in `com.acme.app` can no longer see `oldlib` types — you get errors like *'package org.oldlib is declared in the unnamed module, but module com.acme.app does not read it'* (and there's no `requires` you can add to fix it directly). ### The fix Move `oldlib.jar` from the classpath onto the **module path**. Then: - If it has a `module-info`, it becomes a **named module** with its real name — add `requires <that name>`. - If it's a plain JAR, it becomes an **automatic module** with a derived name (manifest `Automatic-Module-Name` or filename) — add `requires <derived name>`. Either way it now *has a name*, so your named module can require it. ### Why this shapes migration strategy Because named modules can't see the classpath, you generally migrate **top-down**: modularise your application first, declare `requires` on each dependency, and let dependencies that aren't yet modular ride along as **automatic modules** on the module path. You don't have to wait for every library to ship a `module-info`. The unnamed-module rule is the constraint that makes automatic modules necessary — they are the only way a named module can depend on a not-yet-modular JAR.

  • After moving a plain dependency JAR to the module path to fix the error, what name do you put in your requires directive?
    The automatic module name: the value of the Automatic-Module-Name manifest header if present, otherwise the name derived from the JAR's filename (version stripped, non-alphanumerics turned to dots).
  • Can an automatic module access classpath code? Why does that differ from a named module?
    Yes — automatic modules implicitly read the unnamed module, by design, so legacy JARs can still find their classpath dependencies. Named modules are denied this to preserve reliable, explicit configuration.

saying these in an interview costs you the question

  • Saying the rule is arbitrary — it follows from requires being name-based and the unnamed module being nameless
  • Claiming the fix is to add a requires for the unnamed module (impossible — there is no name)
  • Confusing this with automatic modules, which CAN read the unnamed module
  • Thinking putting the JAR back on the classpath solves it — that's what causes it

context