CoreJava Java9

The Java Platform Module System (JPMS) – Java 9 Explained

The Java Platform Module System (JPMS) – Java 9 Explained

The Java Platform Module System (JPMS), also known as Project Jigsaw, is the most significant structural change to the Java platform since its creation. Introduced in Java 9, it allows you to organize code into named modules with explicit dependency declarations and controlled access. This solves long-standing problems with the Java classpath, classpath hell, and unwanted access to internal JDK APIs.

The Problem JPMS Solves

Before Java 9, any code could access any class from any JAR on the classpath. This caused several issues:

  • JAR hell: conflicting library versions with no isolation
  • Weak encapsulation: internal JDK classes (like sun.misc.Unsafe) were accessible and widely used
  • Slow startup: the entire JDK was always available, even if you only needed 5% of it
  • Large deployments: impossible to ship a minimal Java runtime

Key Concepts

Concept Meaning
module A named unit of code with a module descriptor
module-info.java The module descriptor — declares the module's name, dependencies, and exports
requires Declares a dependency on another module
exports Makes a package accessible to other modules
opens Allows deep reflection (needed for frameworks like Spring, Hibernate)
provides / uses Service provider interface declarations

Project Structure


my-app/
├── com.java9r.api/
│   ├── module-info.java
│   └── com/java9r/api/
│       ├── ProductService.java
│       └── Product.java
│
└── com.java9r.app/
    ├── module-info.java
    └── com/java9r/app/
        └── Main.java

Module 1: com.java9r.api (the library module)


// com.java9r.api/module-info.java
module com.java9r.api {
    // Export these packages so other modules can use them
    exports com.java9r.api;

    // Requires the logging module from JDK
    requires java.logging;
}

// com/java9r/api/Product.java
package com.java9r.api;

public class Product {
    private final String id;
    private final String name;
    private final double price;

    public Product(String id, String name, double price) {
        this.id    = id;
        this.name  = name;
        this.price = price;
    }

    public String getId()    { return id; }
    public String getName()  { return name; }
    public double getPrice() { return price; }

    @Override
    public String toString() {
        return "Product{id='" + id + "', name='" + name + "', price=" + price + "}";
    }
}

// com/java9r/api/ProductService.java
package com.java9r.api;

import java.util.List;
import java.util.logging.Logger;

public class ProductService {

    private static final Logger logger = Logger.getLogger(ProductService.class.getName());

    public List<Product> getAllProducts() {
        logger.info("Fetching all products");
        return List.of(
            new Product("P001", "Laptop",     75000.0),
            new Product("P002", "Smartphone", 25000.0),
            new Product("P003", "Tablet",     35000.0)
        );
    }

    public Product findById(String id) {
        return getAllProducts().stream()
                .filter(p -> p.getId().equals(id))
                .findFirst()
                .orElse(null);
    }
}

Module 2: com.java9r.app (the application module)


// com.java9r.app/module-info.java
module com.java9r.app {
    // Depend on the API module
    requires com.java9r.api;

    // JDK modules needed
    requires java.logging;
}

// com/java9r/app/Main.java
package com.java9r.app;

import com.java9r.api.Product;
import com.java9r.api.ProductService;

public class Main {

    public static void main(String[] args) {

        ProductService service = new ProductService();

        System.out.println("=== All Products ===");
        service.getAllProducts().forEach(System.out::println);

        System.out.println("\n=== Find by ID ===");
        Product found = service.findById("P002");
        System.out.println(found != null ? found : "Not found");
    }
}

Compile and Run Modular Code


# Step 1: Compile the API module
javac -d out/com.java9r.api \
      com.java9r.api/module-info.java \
      com.java9r.api/com/java9r/api/*.java

# Step 2: Compile the app module, providing the API module on the module path
javac --module-path out \
      -d out/com.java9r.app \
      com.java9r.app/module-info.java \
      com.java9r.app/com/java9r/app/*.java

# Step 3: Run with module path
java --module-path out --module com.java9r.app/com.java9r.app.Main

Expected Output


=== All Products ===
Product{id='P001', name='Laptop', price=75000.0}
Product{id='P002', name='Smartphone', price=25000.0}
Product{id='P003', name='Tablet', price=35000.0}

=== Find by ID ===
Product{id='P002', name='Smartphone', price=25000.0}

What Happens Without exports?


// If com.java9r.api/module-info.java had NO exports:
module com.java9r.api {
    // exports com.java9r.api;  <-- commented out
}

// Then in Main.java:
import com.java9r.api.Product;  // COMPILE ERROR!
// "package com.java9r.api is not visible"
// "(package com.java9r.api is declared in module com.java9r.api, which does not export it)"

This is strong encapsulation — packages are hidden by default and must be explicitly exported.

JDK Modules (Built-in)


# View all JDK modules:
java --list-modules

# Key JDK modules:
# java.base      – core classes (always available, never needs to be declared)
# java.sql       – JDBC
# java.logging   – java.util.logging
# java.desktop   – Swing, AWT
# java.net.http  – HTTP Client (Java 11+)
# jdk.jshell     – JShell API

Summary

The Java module system solves the classpath hell and weak encapsulation problems that plagued Java applications for decades. By requiring explicit exports declarations, modules hide implementation details by default. requires makes dependencies explicit and verifiable at startup. The module system is especially valuable for large applications and microservices where you want a minimal, optimized Java runtime using jlink. While migrating existing projects to modules requires effort, all new Java projects can benefit from defining a module-info.java from day one.

Topics: CoreJava Java9
← Newer Post Older Post →

Comments

https://www.blogger.com/comment/frame/6690124484600543990?po=4950403867521456666&hl=en&saa=85391&origin=https://www.java9r.com