skip to content

Module System (JPMS)

The Java Platform Module System: module declarations, directives, readability and accessibility, the module types, module path versus classpath, migration pain, services and the tooling. Interviewers ask about it mostly through what broke and why.

part ofJavaoverview, primer and where to startread it →
on this pageshow

explore

questions

page 2 of 2

How does ServiceLoader instantiate providers lazily, and how does the stream()/Provider API let you inspect a provider before creating it?

level: seniorimportance: should knowfreq 40%

basics

~20 s

ServiceLoader only creates a provider object when you actually reach it while iterating, not up front. Since Java 9, ServiceLoader.stream() gives a stream of Provider handles, each exposing type() so you can check the class and call get() to instantiate only the one(s) you want.

open as a page

What is a .jmod file and how does it differ from a regular JAR, and when do you need jmod?

level: seniorimportance: should knowfreq 40%

basics

~20 s

A .jmod file is a packaging format for a module that, unlike a JAR, can also carry native libraries, native commands, config files, and legal/header files. You create and inspect .jmod files with the jmod tool. They are used at link time (by jlink), not at application runtime.

open as a page

Walk through how jdeps, jmod, and jlink work together to ship a minimal runtime, and what breaks the chain.

level: seniorimportance: should knowfreq 38%

basics

~20 s

jdeps analyzes your code to find its dependencies and can draft a module descriptor; jmod packages a module (including native code) into a .jmod; jlink links your modules and their dependencies into a small, self-contained runtime image. The chain breaks mainly on non-modular libraries and on dependencies resolved by reflection.

open as a page

Explain the JPMS escape-hatch flags --add-exports, --add-opens, --add-modules, and --add-reads. When is each needed during migration?

level: principalimportance: should knowfreq 44%

basics

~20 s

These command-line flags relax module rules without editing module-info. --add-exports lets you use a package that isn't exported; --add-opens grants deep reflection into a package; --add-modules forces a module into the graph even if nothing requires it; --add-reads lets one module read another it didn't declare. They are temporary bridges during migration.

open as a page

Your team is upgrading from JDK 8 to JDK 21 and worried about strongly-encapsulated internal APIs. How do you use the JPMS tooling to assess and de-risk this, and what are the tooling's limits?

level: principalimportance: should knowfreq 34%

basics

~20 s

Run jdeps --jdk-internals across all your code and dependency JARs to find usage of internal JDK APIs and their suggested replacements, then fix or replace those before upgrading. Because jdeps is static, also runtime-test, since reflective access to internals won't show up.

open as a page

How do requires, requires transitive, and the readability graph shape module API design and migration at scale?

level: principalimportance: nice to knowfreq 30%

basics

~20 s

requires says your module depends on another. requires transitive also re-exports that dependency to anyone who depends on you, so they read it automatically. The set of who-can-read-whom is the readability graph. Designing these directives well keeps APIs clean and migration manageable.

open as a page

During a JPMS migration, what problems arise from automatic modules and split packages, and how do you reason about them?

level: principalimportance: nice to knowfreq 28%

basics

~20 s

Automatic modules read and export everything, so they give no real encapsulation and their derived names can be unstable. JPMS also forbids the same package being supplied by two modules (a split package), which legacy JARs often violate — that causes resolution failures you must resolve by merging or relocating packages.

open as a page

Given a real project, how do you decide whether to ship on the classpath or fully adopt the module path, and what are the trade-offs?

level: principalimportance: nice to knowfreq 22%

basics

~20 s

Use the module path when you want enforced boundaries, a validated dependency graph, and small custom runtimes (jlink). Stay on the classpath when the ecosystem you depend on isn't modularized, reflection-heavy frameworks fight encapsulation, or the migration cost outweighs the benefit.

open as a page

Strong encapsulation in JPMS is a deliberate trade-off. As a module designer, how do you decide what to `exports`, what to `opens`, and how do you keep the surface minimal?

level: principalimportance: nice to knowfreq 35%

basics

~20 s

Export only the packages that form your public API; keep everything else internal. Open packages only for the specific reflection-based frameworks that truly need them, and qualify those opens to just those frameworks. The default should be closed.

open as a page

When should you reach for ServiceLoader/SPI versus a dependency-injection framework or a hand-rolled plugin registry? What are the design tradeoffs?

level: principalimportance: nice to knowfreq 28%

basics

~20 s

Use ServiceLoader/SPI when you want zero-dependency, JDK-native plug-in discovery — third parties extend your library by dropping in a jar/module. Use a DI framework when you need rich lifecycle, scoping, and wiring of many beans inside one app. SPI is for open extension points; DI is for assembling your own application's objects.

open as a page

showing 31–40 of 40