🪞 Reflection, Annotations & Modules · Advanced

Classpath vs module path in Java

Unnamed and automatic modules.

🧩 The mysteryYour app has 200 JARs and none of them have module-info. Do you have to wait for every library to modularize before you can use modules? Java planned for that.

The unnamed module

Everything on the class path lands in one unnamed module. It reads every module and exposes all its packages, which is the old, pre-module behavior. But it has no name, so a named module can't require it.

Automatic modules

A plain JAR (no module-info) placed on the module path becomes an automatic module. It reads everything and exports everything, and it gets a name: from the Automatic-Module-Name manifest entry, or else derived from the file name. A JAR with module-info.class is an explicit module.

🔮 Predict it

Guess the name

my-utils-1.2.jar has no Automatic-Module-Name. What's its automatic module name?

  1. my.utils
  2. my-utils-1.2
  3. my_utils_1_2
Show the answer

**my.utils**. The .jar and the version (-1.2) are dropped, and characters that aren't letters or digits become dots.

⚠️ The trap

Requiring the class path

A named module cannot require the unnamed module: there's no name to write. That's exactly why automatic modules exist: they give old JARs a name your module can require.

module com.shop.app {
    requires unnamed; // no such thing
}

Naming a library that isn't modular yet

✗ Derived from file name
my-utils-1.2.jar  ->  my.utils

Breaks users' requires clauses when the file is renamed.

✓ Reserved in the manifest
Automatic-Module-Name: com.acme.utils

Stable name now; the real module-info can arrive later.

🤔 Think first

Two JARs, one package

Two JARs on the module path both contain the package com.util. What happens?

Think about it, then reveal the answer

Startup fails: a package may belong to only one module (no split packages). On the class path the same setup "works", but the first JAR silently wins, causing subtle bugs. JPMS turns that into a clear error.

💼 In the real world

Step-by-step migration

Real migrations are gradual: keep most JARs on the class path, move modular libraries to the module path, and let old ones run as automatic modules. Library authors usually start by adding Automatic-Module-Name, then a real module-info later.

Key takeaways

  1. Class path: one unnamed module, the old behavior
  2. Plain JAR on module path: automatic module
  3. Automatic modules read everything and export everything
  4. Automatic-Module-Name gives a stable name
🤯 Did you know?

Many popular libraries shipped an Automatic-Module-Name manifest entry long before adding a real module-info, just to reserve their module name.

Practice questions

A JAR named my-utils-1.2.jar has no Automatic-Module-Name. What name does it get as an automatic module?

  1. unnamed
  2. my_utils_1_2
  3. my-utils-1.2
  4. my.utils
Check your answer

my.utils. The version is dropped and non-alphanumeric characters become dots. Because file names can change, library authors should set Automatic-Module-Name.

A library hasn't added module-info yet, but wants users to have a stable module name. What should the author do?

  1. Rename the JAR on every release
  2. Add Automatic-Module-Name to the JAR manifest
  3. Put the JAR in the JDK's lib folder
  4. Nothing; names are random anyway
Check your answer

Add Automatic-Module-Name to the JAR manifest. Automatic-Module-Name reserves the name now, so users' `requires` clauses keep working when the real module-info arrives later.

Modules hide implementations. So how does an app find an implementation it can't even name? Next: ServiceLoader.