Java Module System (Project Jigsaw)

Loading

Java Module System, introduced in Java 9 as part of Project Jigsaw, is a significant enhancement to the Java platform. It provides a way to modularize Java applications and the JDK itself, improving scalability, maintainability, and security. Below is a comprehensive guide to understanding and using the Java Module System.


1. What is the Java Module System?

  • Definition: A system for creating modular applications by encapsulating code into modules.
  • Purpose:
  • Strong Encapsulation: Hide internal implementation details.
  • Reliable Configuration: Explicitly declare dependencies between modules.
  • Scalability: Improve the scalability of large applications and the JDK.

2. Key Concepts

a. Module

  • Definition: A self-contained unit of code and data with a well-defined interface.
  • Module Descriptor: Defined in a module-info.java file.
  module com.example.mymodule {
      requires java.base;
      requires java.sql;
      exports com.example.mymodule.api;
  }

b. Module Path

  • Definition: A path where the module system looks for modules.
  • Usage: Replace the classpath with the module path (--module-path).

c. Module Types

  1. Named Modules: Explicitly defined modules with a module-info.java file.
  2. Automatic Modules: JARs without a module-info.java file, automatically converted to modules.
  3. Unnamed Module: The default module for code not part of any named or automatic module.

3. Creating a Modular Application

Step 1: Define Modules

  • Create a module-info.java file for each module.
  // module-info.java for com.example.mymodule
  module com.example.mymodule {
      requires java.base;
      requires java.sql;
      exports com.example.mymodule.api;
  }

Step 2: Compile Modules

  • Use the javac command with the --module-source-path option.
  javac --module-source-path src -d out $(find src -name "*.java")

Step 3: Package Modules

  • Use the jar command to package modules.
  jar --create --file=lib/mymodule.jar -C out/com.example.mymodule .

Step 4: Run Modules

  • Use the java command with the --module-path and --module options.
  java --module-path lib -m com.example.mymodule/com.example.mymodule.Main

4. Module Descriptor Directives

a. requires

  • Specifies a dependency on another module.
  requires java.sql;

b. exports

  • Exports a package to other modules.
  exports com.example.mymodule.api;

c. opens

  • Opens a package for reflection (e.g., for frameworks like Hibernate).
  opens com.example.mymodule.internal;

d. uses and provides

  • uses: Specifies a service interface.
  uses com.example.mymodule.spi.MyService;
  • provides: Specifies a service implementation.
  provides com.example.mymodule.spi.MyService with com.example.mymodule.MyServiceImpl;

5. Modular JDK

  • JDK Modules: The JDK itself is modularized into several modules (e.g., java.base, java.sql).
  • Viewing JDK Modules:
  java --list-modules

6. Migrating to Modules

a. Bottom-Up Migration

  • Start by modularizing the lowest-level libraries and work upwards.

b. Top-Down Migration

  • Start by modularizing the application and work downwards.

c. Using Automatic Modules

  • Convert existing JARs to automatic modules by placing them on the module path.

7. Best Practices

  1. Start Small: Begin with a few modules and gradually modularize the application.
  2. Use Strong Encapsulation: Hide internal implementation details by not exporting unnecessary packages.
  3. Leverage Services: Use the uses and provides directives for loose coupling.
  4. Test Thoroughly: Ensure compatibility and functionality after modularization.

8. Common Issues and Troubleshooting

  • Module Not Found: Ensure the module is on the module path and the module name is correct.
  • Package Not Exported: Ensure the package is exported in the module descriptor.
  • Reflection Issues: Use opens to allow reflection on internal packages.

Resources


Leave a Reply

Your email address will not be published. Required fields are marked *