Java Modules (JPMS)

Modules let you define clear boundaries in large applications by specifying which packages are available to others and which dependencies you need. You declare them in a module-info.java file at the root of your module.

// module-info.java
module com.example.app {
    requires com.example.utils;       // needs another module
    requires java.sql;                // needs a standard module

    exports com.example.app.api;      // makes this package public
    opens com.example.app.internal;   // allows deep reflection
}

requires

Lists modules your code depends on. The compiler and runtime ensure these are present.

requires java.base;      // implicitly added, contains core Java
requires java.logging;   // for java.util.logging APIs

exports

Makes a package available at compile time and runtime to other modules.

exports com.example.service;  

Clients can then requires com.example.app; and import types from com.example.service.


opens

Grants runtime reflective access (for frameworks like Jackson or Spring) but does not allow compile-time access.

opens com.example.model; 

Your JSON mapper can use reflection to read/write private fields in com.example.model.


uses & provides

Enable a service-loader pattern for loose coupling.

// In module A (consumer)
uses com.example.spi.PaymentProcessor;

// In module B (provider)
provides com.example.spi.PaymentProcessor
    with com.example.impl.CreditCardProcessor;

At runtime, ServiceLoader.load(PaymentProcessor.class) finds all providers automatically.


Other Options

exports com.example.secret to com.example.trusted;
opens com.example.reflection to org.junit.jupiter.api;

With modules, you gain strong encapsulation, better performance, and safer class loading, making large-scale Java applications more maintainable and secure.


Classes
Quiz
Videos
References
Books