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.Unsafe were 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
  

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 exports sparingly — expose only public API packages
  • Use opens only for frameworks that need reflection (JPA, Spring)
  • Run jdeps to analyze dependencies before modularizing
  • Do not rely on internal JDK packages — they are strongly encapsulated since Java 9