On this page
JPMS Overview
The Java Platform Module System (JPMS), introduced in Java 9 (Project Jigsaw), organizes code into modules with explicit dependencies and encapsulated packages.
Why Modules?
Before Java 9, the JDK was one monolithic JAR — any public class was accessible. Problems:
- Encapsulation leaks — Internal APIs like
sun.misc.Unsafewere widely used - Classpath hell — JAR conflicts and missing dependencies at runtime
- Large runtime — Entire JDK required even for small apps
JPMS solves these with strong encapsulation and explicit dependencies.
Module Basics
A module is a named set of packages with a module-info.java descriptor:
// module-info.java
module com.example.myapp {
requires java.logging;
requires java.sql;
exports com.example.myapp.api;
opens com.example.myapp.internal to spring.core;
}
com.example.myapp/
├── module-info.java
├── com/example/myapp/
│ ├── api/
│ │ └── UserService.java (exported)
│ └── internal/
│ └── UserRepository.java (encapsulated)
Key Directives
| Directive | Purpose |
|---|---|
requires |
Depends on another module |
exports |
Makes a package public to other modules |
opens |
Allows reflective access to a package |
provides |
Declares a service implementation |
uses |
Declares a service dependency |
Running Modular Applications
# Compile
javac -d out --module-source-path src $(find src -name "*.java")
# Run
java --module-path out --module com.example.myapp/com.example.myapp.Main
# Run with automatic modules from JARs on module path
java --module-path libs:out --module com.example.myapp/com.example.myapp.Main
JDK Modules
The JDK is split into ~70 modules. Common ones:
| Module | Contents |
|---|---|
java.base |
Core classes (always required, not named) |
java.logging |
java.util.logging |
java.sql |
JDBC API |
java.xml |
XML processing |
java.net.http |
HTTP Client (Java 11+) |
jdk.httpserver |
Embedded HTTP server |
# List all JDK modules
java --list-modules
# Show module details
java --describe-module java.sql
Automatic Modules
A plain JAR on the module path (not classpath) becomes an automatic module:
- Name derived from JAR filename (hyphens → dots)
- Exports all packages
- Reads all other modules
java --module-path mylib.jar:out --module com.example.app/com.example.Main
jlink — Custom Runtime
Create a minimal runtime with only required modules:
jlink --module-path $JAVA_HOME/jmods:out \
--add-modules com.example.myapp \
--launcher myapp=com.example.myapp/com.example.Main \
--output myapp-runtime
See jlink & jpackage for details.
Migration Path
| Stage | Description |
|---|---|
| Classpath app | Works unchanged on Java 9+ |
| Automatic module | Place JARs on module path |
| Full module | Add module-info.java |
| Custom runtime | Use jlink for minimal deployment |
Best Practices
- Start modularizing new projects with
module-info.java - Use
exportssparingly — expose only public API packages - Use
opensonly for frameworks that need reflection (JPA, Spring) - Run
jdepsto analyze dependencies before modularizing - Do not rely on internal JDK packages — they are strongly encapsulated since Java 9