Introduction to Java Modules and Project Jigsaw
Table of Contents
Fundamental Concepts
What is Project Jigsaw?
Project Jigsaw is an initiative to introduce a standard module system to the Java platform. It was developed to solve several long - standing problems in Java, such as the lack of strong encapsulation, large monolithic JRE, and difficulty in managing dependencies in large projects.
Java Modules
A Java module is a self - contained unit of code that has a well - defined set of classes and resources. It can specify which of its packages are accessible to other modules (exports) and which other modules it depends on (requires).
The module-info.java file is the heart of a Java module. It is a special file that must be placed in the root of the module’s source directory. Here is a simple example of a module-info.java file:
// module-info.java
module com.example.myModule {
exports com.example.myPackage;
requires java.base;
}
In this example:
module com.example.myModuledeclares a module namedcom.example.myModule.exports com.example.myPackagemakes thecom.example.myPackagepackage accessible to other modules.requires java.baseindicates that this module depends on thejava.basemodule, which is the foundation module of the Java platform.
Usage Methods
Creating a Simple Module
Let’s create a simple Java module. First, create a directory structure for your module:
myModule/
├── src/
│ └── com/
│ └── example/
│ └── myPackage/
│ ├── MyClass.java
│ └── module-info.java
Here is the code for MyClass.java:
// MyClass.java
package com.example.myPackage;
public class MyClass {
public static void sayHello() {
System.out.println("Hello from MyClass!");
}
}
And the module-info.java file:
// module-info.java
module com.example.myModule {
exports com.example.myPackage;
}
Compiling a Module
To compile the module, you can use the javac command:
javac -d mods/com.example.myModule src/com/example/myPackage/*.java src/module-info.java
Running a Module
You can create a simple application that uses this module. Create another module that depends on com.example.myModule:
myApp/
├── src/
│ └── com/
│ └── example/
│ └── myApp/
│ ├── Main.java
│ └── module-info.java
Here is the code for Main.java:
// Main.java
package com.example.myApp;
import com.example.myPackage.MyClass;
public class Main {
public static void main(String[] args) {
MyClass.sayHello();
}
}
And the module-info.java file:
// module-info.java
module com.example.myApp {
requires com.example.myModule;
}
Compile the myApp module:
javac -p mods -d mods/com.example.myApp src/com/example/myApp/*.java src/module-info.java
Run the application:
java -p mods -m com.example.myApp/com.example.myApp.Main
Common Practices
Dependency Management
When working with Java modules, it’s important to manage dependencies correctly. Only require the modules that your module actually needs. This helps in reducing the size of the application and improving security.
Encapsulation
Use the exports statement carefully. Only export the packages that need to be accessed by other modules. This helps in hiding the internal implementation details of your module.
Versioning
Although Java modules do not have built - in versioning, you can use external tools like Maven or Gradle to manage module versions. This is important for maintaining compatibility between different versions of modules.
Best Practices
Use Module - Specific Services
Java modules support the concept of services. A service is an interface or an abstract class, and service providers are implementations of that service. By using services, you can achieve loose coupling between modules.
Here is an example of a service interface:
// ServiceInterface.java
package com.example.service;
public interface ServiceInterface {
void performAction();
}
And a service provider:
// ServiceProvider.java
package com.example.service.impl;
import com.example.service.ServiceInterface;
public class ServiceProvider implements ServiceInterface {
@Override
public void performAction() {
System.out.println("Service action performed!");
}
}
In the module-info.java of the service provider module, you can declare the service:
// module-info.java
module com.example.serviceModule {
provides com.example.service.ServiceInterface with com.example.service.impl.ServiceProvider;
exports com.example.service;
}
Keep Modules Small and Cohesive
Each module should have a single, well - defined responsibility. This makes the modules easier to understand, test, and maintain.
Conclusion
Java Modules and Project Jigsaw have brought a new level of modularity to the Java platform. By understanding the fundamental concepts, usage methods, common practices, and best practices, developers can build more robust, secure, and maintainable Java applications. The module system helps in managing dependencies, improving encapsulation, and enabling better code organization.