skip to content

What is module readability in JPMS, and how does a module obtain it?

level: juniorimportance: should knowfreq 55%

answer

  1. Readability = 'A may depend on B' via `requires B`
  2. Access needs BOTH readability AND accessibility
  3. java.base is read implicitly
  4. requires transitive = implied readability for re-exposed API types
  5. requires static = compile-time only, optional at run time

basics

~10 s

Readability means one module is allowed to depend on another. Module A reads module B when A's module-info.java says requires B. Without that, A cannot use B's types at all.

solid answer

~50 s

Readability is the dependency relationship between modules. Module A *reads* module B if A can use B's exported types. You establish it with a `requires` directive in A's `module-info.java`: `requires B;`. Readability is one of the two conditions for access — a type in B is usable from A only if (1) A reads B AND (2) the type is public and in a package B exports. Every module implicitly reads `java.base`. There are two important variants: `requires transitive B` means anyone who reads A also automatically reads B (implied readability — used when A's public API exposes B's types); and `requires static B` means B is needed at compile time but is optional at run time (for example, annotation libraries). Readability is also resolved by the module graph at startup, so a missing required module fails fast rather than at first use.

code

java · 6 lines
java
module com.example.a {
    requires com.example.b;              // A reads B
    requires transitive com.example.c;   // A reads C, AND anyone reading A also reads C
    requires static com.example.anno;    // needed to compile, optional at run time
    // (java.base is read implicitly — never declared)
}

go deeper

for a junior

Knows readability means a module can depend on another and is set up with requires.

for a middle

States the two access conditions (readability + accessibility) and knows java.base is implicit.

for a senior

Chooses requires transitive vs plain requires based on whether re-exposed types appear in the public API, and explains requires static and startup resolution.

for a principal

Designs module dependency graphs to minimize transitive coupling, uses qualified/transitive requires deliberately, and reasons about resolution and migration (automatic modules, split packages) at scale.

## What readability is In the **Java Platform Module System (JPMS)**, a **module** is a named group of packages described by `module-info.java`. Modules form a graph. **Readability** is the directed edge in that graph: if module **A reads module B**, then A is permitted to depend on B — to see and use the types B makes available. If A does not read B, then *nothing* in B is visible to A, even B's exported public types. Readability is therefore the first gate. ## How you obtain readability: `requires` You declare it in the consuming module: ```java module com.example.a { requires com.example.b; // A now reads B } ``` That single directive makes the edge A → B. After this, A can use the *exported* public types of B. ## The two conditions for access Readability alone is not enough. For code in A to use a type `T` defined in B, **both** must hold: 1. **Readability:** A reads B (`requires com.example.b`). 2. **Accessibility:** `T` is `public` *and* lives in a package that B `exports`. Missing either one means A cannot touch `T`. (This pairing — readability + accessibility — is the heart of module access rules. Reflection adds a third concept, `opens`, covered separately.) ## Implicit readability of `java.base` Every module automatically reads `java.base` (the module containing `java.lang`, `java.util`, etc.) without declaring it. That is why you never write `requires java.base;` — it is implied. ## `requires transitive` — implied readability Sometimes A's *public API* mentions types from B. For example, a method in A returns a `com.example.b.Widget`. Any module C that uses that method must also read B, or it cannot even name the return type. Forcing every C to add `requires B` is fragile. Instead, A declares: ```java requires transitive com.example.b; ``` Now any module that reads A **implicitly also reads B**. This is called *implied readability*. Rule of thumb: if a type from B appears in A's exported (public) signatures, use `requires transitive`; if B is purely an internal implementation detail, use plain `requires`. ## `requires static` — optional at run time ```java requires static com.example.annotations; ``` `requires static` means the dependency is needed to **compile** but is **optional at run time**. Common for compile-time-only annotation libraries or optional integrations: the module compiles against them, but if they are absent at run time, the module still loads. ## Resolution at startup When the JVM starts, it resolves the module graph from the root modules, following `requires` edges. If a required module is missing, you get a clear error at startup (e.g. *module not found*), not a mysterious failure deep into execution. This fail-fast behavior is a key benefit over the old classpath. ## Summary - Readability = "A may depend on B", created by `requires B` in A. - It is the *first* of the two access conditions; the second is accessibility (public + exported). - `java.base` is read implicitly. - `requires transitive` propagates readability to A's consumers (for re-exposed API types). - `requires static` = compile-time-only / optional-at-runtime dependency.

  • When should you prefer `requires transitive` over plain `requires`?
    When types from the required module appear in your module's own exported (public) API — for example as parameter or return types of public methods. Then consumers of your module need to read that module too, and `transitive` grants that automatically (implied readability). Keep it plain `requires` when the dependency is only an internal implementation detail.

Readability is like having someone's phone number: without it you cannot call them at all. Having the number (requires) still does not mean you can ask about everything — that depends on what they choose to share (exports/accessibility).

saying these in an interview costs you the question

  • Believing `requires` alone makes all of a module's types usable — you still need the type to be public and its package exported.
  • Writing `requires java.base;` — it is implicit and redundant.
  • Confusing `requires transitive` with `requires static`; one propagates readability, the other marks an optional-at-runtime dependency.
  • Thinking readability is bidirectional — it is a directed edge (A reads B does not mean B reads A).

context