skip to content

How does an automatic module get its name, and why is relying on the filename-derived name risky?

level: middleimportance: should knowfreq 40%

answer

  1. First: Automatic-Module-Name manifest header (stable, preferred)
  2. Else: derive from filename -> strip version, non-alnum runs become dots
  3. guava-32.1.jar -> 'guava'; commons-lang3-3.12.jar -> 'commons.lang3'
  4. Filename name changes if the file is renamed/re-versioned
  5. Illegal derived name (e.g. leading digit) makes the JVM reject the JAR

basics

~20 s

An automatic module's name comes from the Automatic-Module-Name entry in the JAR's MANIFEST.MF if present. If not, Java derives it from the JAR filename (dropping the version and turning non-letters/digits into dots). Filename-derived names are risky because renaming the file changes the module name.

solid answer

~50 s

When a plain JAR sits on the module path it becomes an automatic module, which needs a name. Java looks first at the `MANIFEST.MF` for an `Automatic-Module-Name:` header and uses that value if present — this is the intended, stable mechanism for library authors. If the header is absent, Java derives the name from the **filename**: it strips a trailing version (like `-1.2.3`), then replaces every run of non-alphanumeric characters with a single dot, so `commons-lang3-3.12.jar` becomes module name `commons.lang3`. The risk with filename derivation is fragility: the name is an accident of how the file happens to be named, so renaming or re-versioning the artifact can silently change the module name, breaking every `requires` that referenced the old name. It can also produce illegal names (e.g. a leading digit) that fail outright. That's why teams should depend on libraries that publish `Automatic-Module-Name`, or pin the file name carefully until they do.

go deeper

for a junior

Knows automatic modules get a name automatically and that a manifest header can set it.

for a middle

Explains both sources (manifest header, then filename derivation) and the rough derivation rule, and knows filename names are less stable.

for a senior

Describes the exact derivation steps, the version-stripping heuristic, and the concrete failure modes (rename breaks requires, illegal name rejected) plus the manifest-header remedy.

for a principal

Sets org-wide policy: require Automatic-Module-Name from dependencies, treat filename-derived names as build hazards, and weigh repackaging/shading vs. waiting for upstream.

## Why an automatic module needs a name at all A module's whole identity in JPMS is its **name**: other modules reference it with `requires <name>`, and the runtime keys the module graph on names. An **automatic module** is a plain (non-modular) JAR placed on the **module path**; it has no `module-info` declaring a name, yet it must have one so that named modules can depend on it. So the system must *synthesise* a name. It uses a two-step rule. ## Step 1: the manifest header (the good path) Java first inspects the JAR's `META-INF/MANIFEST.MF` for a header: ``` Automatic-Module-Name: org.apache.commons.lang3 ``` If present, **that value is the module name**, full stop. This is the mechanism library authors are encouraged to use: it lets a project claim a stable, intentional module name *before* it does the full work of adding a `module-info`. Downstream users can then `requires org.apache.commons.lang3` and trust it won't change when the library is updated. It is the recommended first step of any library's modularisation. ## Step 2: derive from the filename (the fragile fallback) If there is **no** such header, Java derives the name from the **JAR file's name** using a fixed algorithm: 1. Drop the `.jar` extension. 2. If the remaining name ends in a version-like suffix (a hyphen or underscore followed by a digit, e.g. `-3.12.0`), strip that suffix off — the part before it is the name, the part after becomes the module's *version*. 3. In what remains, replace every run of non-alphanumeric characters (dots, hyphens, etc.) with a single `.`, and collapse repeats. Examples: - `guava-32.1.0-jre.jar` -> name `guava` (with version `32.1.0-jre`). - `commons-lang3-3.12.0.jar` -> name `commons.lang3`. - `my-cool-lib.jar` -> name `my.cool.lib`. ## Why filename derivation is risky **1. The name is an accident of packaging.** Nothing about the library's identity is encoded; the name reflects how the file *happened* to be named. If a build tool, mirror, or developer renames the artifact (a common occurrence — different repos name files differently), the derived module name changes, and every `requires` that referenced the old name no longer resolves. Your build breaks for a reason that has nothing to do with code. **2. Re-versioning can shift the name.** The version-stripping heuristic only triggers on a digit after a hyphen/underscore. Oddly-versioned files can be parsed differently across versions, producing a different name token. **3. It can yield an illegal module name.** A derived name must be a valid Java identifier sequence — it cannot start with a digit, contain a keyword as a segment, etc. If derivation produces something illegal (e.g. a filename beginning with a number), the JVM **rejects the JAR outright** with an error, rather than guessing. **4. No coordination.** Two different files could derive the same name, or the 'right' name a library wants is unobtainable from its filename, leading to collisions or awkward `requires`. ## The practical guidance For library authors: ship `Automatic-Module-Name` in the manifest as soon as possible — it's a one-line, backward-compatible change that pins a stable name long before you write a `module-info`. For consumers: prefer dependencies that publish the header; if a dependency only has a filename-derived name, treat that name as unstable, avoid pinning critical wiring to it, and push the upstream project (or shade/repackage) until it provides a real name. The general lesson: **never let an automatic module's name be left to chance when other modules' `requires` depend on it.**

  • What happens if the filename-derived module name would be illegal (for example the file starts with a digit)?
    The JVM does not guess a fallback — it rejects the JAR on the module path with an error like 'Unable to derive module descriptor', so the only fix is to rename the file or have the JAR declare an Automatic-Module-Name.
  • As a library maintainer, what is the cheapest way to give consumers a stable module name before doing full modularisation?
    Add a single Automatic-Module-Name header to the JAR's MANIFEST.MF; it pins a stable name, requires no module-info, and stays fully usable on the classpath too.

saying these in an interview costs you the question

  • Saying the name comes from the JAR's package structure — it does not
  • Believing the filename-derived name is stable across renames/versions
  • Forgetting the manifest header takes precedence over the filename
  • Assuming derivation always succeeds — an illegal name causes a hard failure

context