Java Platform Module System: What and Why

A module is a set of packages designed for reuse.

Alex Buckley, author of the Java language
Modules in JDK 9 by Alex Buckley

Concretely, a Module…

  • Is a group of related packages and resources + a module-info.java-file.
  • Uses a module-info.java-file, at the root of the module’s directory, to provide metadata about the module.
module be.multimedi.library.core {
    exports be.multimedi.library.core.model;
    exports be.multimedi.library.core.util;
}
  • Notice how we gave our module a name.
    • We normally use the package name for consistency, clarity and avoiding conflicts.
  • Notice how we’re able to specify which packages we do/don’t want to expose.
    • By default packages are inaccessible, we specify the ones we wanna export.
  • Until now it was never possible to dictate accessibility and groupings in packages, as you can’t write code or access modifiers on a package or group of packages directly.
    • All public types (classes, interfaces, fields, methods etc.) are freely accessible by all code in the same application.
    • This leads to inadvertent dependencies on code that the developers never intended for public use.
    • So, when the developers change this code, our code breaks.
    • Lacking encapsulation (a clear distinction between “Yes, this is for public use, go ahead” and “Nah, this is for internal use only”) leads to reduced maintainability.
  • The JPMS allows developers to create modules by attaching meta-information about a group of packages, making JARs more than just containers.
  • This metadata states the developer’s intent for the module’s identity, purpose and relationship with other modules.
    • Defines its own namespace, isolating its components from the rest of the application.
    • Specifies its dependencies explicitly, ensuring a clear and manageable architecture.
    • Encapsulates its internal implementation details, controlling access to its API.
    • Provides versioning and encapsulation boundaries, promoting long-term stability.
  • Using modules, both the developers and Java (during compilation and runtime) understand the identity, purpose and relationships between modules, and we can thus solve problems like missing or duplicate dependencies more easily.

Advantages of Using Modules

  • Better access control
    • With public, protected, package private and private, we can limit and control access to a type.
    • What if we want to limit access when it comes to packages? What if we only want to expose a select amount of our packages with fine-grained control?
    • Modules provide a higher level of access control.
    • With the module descriptor (module-info.java-file) we specify which packages we want to expose for stronger encapsulation, we declare our dependencies, and name our module.
    • This allows us to differentiate between private packages for internal use, and public packages intended for external use.
  • Better code quality
    • Encourages us to think modularly.
    • To be conscious of logical organisation of our code.
    • To separate our code by concern (Single Responsibility Principle).
    • This naturally results in loose coupling.
  • Better dependency management
    • We can now explicitly specify our module’s dependencies in the module descriptor.
    • This makes it not only clear to us developers, but also lets Java help us during compilation and runtime to track down and fix any dependency issues, because now Java knows what our intentional dependencies are.
  • Lighter JRE
    • JDK is > 150MB.
    • By specifying the necessary JDK-modules, and by using the jlink-tool, developers can have their programs run on a lighter version of the JRE.
    • This also has the added side-effect benefit of increased security: if there’s a security vulnerability in one of the modules, and your application doesn’t use that module, you won’t be affected.
  • Better performance
    • Java knows which modules it needs now thanks to JPMS.
    • The JVM will only search for those modules during class-loading.
    • Improves startup-time.
    • Reduces memory footprint.
    • More info on this topic can be found on the JSR 376.

The Module Path

  • Introduced alongside the Java Platform Module System in Java 9.
  • Modern alternative to the traditional classpath, designed specifically to work with modules.
  • A way of specifying the location of Java modules to the Java runtime, similar to the classpath, except modules are defined in a structured manner with defined dependencies and exports.

Module Path vs. Classpath

FeatureClasspathModule Path
OrganizationUnstructured, flat. All classes and packages are accessible indiscriminately.Structured and hierarchical. Modules explicitly define dependencies and accessible packages.
Dependency HandlingManual management, prone to errors and conflicts such as “JAR hell”.Dependencies are explicitly declared and managed, reducing conflicts and ensuring more reliable configurations.
VisibilityAll packages are indiscriminately visible to the class loader, potentially exposing internal APIs.Strong encapsulation by default. Only explicitly exported packages are visible outside the module.
UsageUsed with traditional Java applications.Recommended for new applications to leverage modularity for better encapsulation and dependency management.
InteroperabilityOnly operates within the traditional loading mechanism, without awareness of module boundaries.Can coexist with classpath to support hybrid applications during transition. Modules can explicitly specify allowed reflective access.

Example: Setting the Module Path

When compiling and running Java applications, the --module-path (abbreviated to -p) option is used to specify the path to modules. Here’s how you might compile and run a modular application:

  1. Compilation:
javac -p lib -d out --module-source-path src/com/example/MyApp/module-info.java src/com/example/MyApp/MyApp.java
  1. Running:
java -p out --module com.example.myapp/com.example.myapp.MyApp