Java - Java Module System (JPMS) – Detailed Explanation
The Java Module System, officially introduced in Java 9, is a major enhancement to the Java platform that brings modularity to Java applications. It is also commonly referred to as JPMS (Java Platform Module System). Before this, Java applications were organized using packages and JAR files, but there was no strong mechanism to control dependencies or encapsulation at a higher level. JPMS addresses these limitations.
1. What is a Module?
A module is a self-contained unit of code that includes:
-
Packages (classes and interfaces)
-
A description of its dependencies
-
A definition of which parts are accessible to other modules
Each module is defined by a special file called:
module-info.java
This file acts as the module’s descriptor and is placed at the root of the module.
2. Structure of a Module
A typical module structure looks like this:
-
module-info.java
-
com/example/package1/
-
com/example/package2/
The module-info.java file contains directives that define:
-
Module name
-
Required dependencies
-
Exported packages
Example:
module com.example.myapp {
requires java.sql;
exports com.example.myapp.api;
}
3. Key Directives in JPMS
requires
This specifies dependencies on other modules.
Example:
requires java.base;
Every module implicitly depends on java.base, which contains fundamental classes like String and Object.
exports
This makes a package accessible to other modules.
Example:
exports com.example.service;
If a package is not exported, it is completely hidden from other modules, even if the classes are public.
requires transitive
This allows dependency propagation.
Example:
requires transitive java.logging;
If Module A requires Module B transitively, and Module C depends on Module A, then Module C automatically reads Module B.
opens
This is used for reflection.
Example:
opens com.example.model;
It allows runtime access (for frameworks like Hibernate or Spring) without making the package publicly accessible at compile time.
uses and provides
These support service-based architecture.
Example:
uses com.example.service.PaymentService;
provides com.example.service.PaymentService with com.example.impl.PaymentServiceImpl;
This enables loose coupling using service loaders.
4. Strong Encapsulation
One of the most important features of JPMS is strong encapsulation.
Before JPMS:
-
Public classes were accessible everywhere.
With JPMS:
-
Only exported packages are accessible.
-
Internal implementation details remain hidden.
This improves:
-
Security
-
Maintainability
-
Code clarity
5. Benefits of JPMS
Better Dependency Management
Modules explicitly declare dependencies, reducing hidden or accidental dependencies.
Improved Security
Internal packages are hidden unless explicitly exported.
Faster Startup and Smaller Applications
Unused modules can be excluded, reducing runtime footprint.
Reliable Configuration
Eliminates issues like classpath conflicts and “JAR hell.”
6. Module Path vs Classpath
JPMS introduces a new concept called module path.
-
Classpath: Traditional way of loading classes (no structure or dependency rules)
-
Module Path: Structured, enforces module boundaries and dependencies
When using JPMS, applications are typically run using the module path instead of the classpath.
7. Types of Modules
Named Modules
Modules with a module-info.java file.
Automatic Modules
Existing JARs placed on the module path without module-info.java. Their names are derived automatically.
Unnamed Module
Code on the classpath belongs here. It has no module name and can access everything but cannot be accessed by named modules in a controlled way.
8. Migration to JPMS
Migrating existing applications involves:
-
Identifying dependencies
-
Creating module-info.java
-
Resolving split packages and cyclic dependencies
Challenges may include:
-
Legacy libraries not supporting modules
-
Reflection-related issues
9. Real-World Usage
JPMS is widely used in:
-
Large enterprise systems
-
Microservices architectures
-
Framework development
It is especially useful when building scalable and maintainable applications with clear boundaries between components.
10. Limitations
-
Initial learning curve is high
-
Not all third-party libraries fully support modules
-
Can introduce complexity in small applications
Conclusion
The Java Module System is a powerful feature that transforms how Java applications are structured. By introducing modular architecture, it improves dependency management, encapsulation, and scalability. While it may not be necessary for small projects, it becomes highly valuable in large and complex systems where maintainability and reliability are critical.