Introduction to the Java Module System (Jigsaw)
Starting with Java 9, the Java platform received one of its biggest updates with the introduction of the module system, also known as Project Jigsaw. This project's main objective was to make Java more scalable for small devices, improve performance, facilitate the maintenance and evolution of Java libraries and applications, as well as offering a safer and more robust system in terms of code encapsulation.
What are Modules?
A module is a grouping of code and data that provides complete functionality and can be independently compiled and distributed. In the context of Java, a module can contain one or more packages, and is defined by a special file called module-info.java
. This file explicitly declares which packages the module exports to be used by other modules, which modules are necessary for its operation and which services it offers or consumes.
Why Modules?
Before the module system, Java used the classpath to locate its classes and libraries. However, the classpath had several disadvantages: it was error-prone, it did not offer a means of expressing dependencies, and it did not enforce any kind of strong encapsulation. With the module system, each module has an isolated namespace, which reduces conflicts and makes the system more secure and easier to manage.
Module System Components
Java's module system is made up of several key components:
- module-info.java: The module definition file, which contains module declarations, exports, and dependencies.
- jmod: A new file format that allows you to package modules for distribution.
- jlink: A tool that allows you to create custom runtime images containing only the modules needed by an application.
Defining a Module
A module is defined by a module-info.java
file in the root of the module's source directory. This file contains the module declaration, which begins with the keyword module
, followed by the module name, and a block that can contain the following directives:
module com.myapp {
requires java.sql;
exports com.myapp.util;
provides com.meuapp.servicos.InterfaceServico
with com.meuapp.servicos.ImplementacaoServico;
}
Here, requires
is used to specify a dependency on another module, exports
to declare which packages are available to other modules, and provides
with with
to define a service offered by the module.
Resolving Dependencies
With the module system, dependencies are resolved at compile time, which means that all necessary modules must be available for the compilation to be successful. This eliminates the "JAR hell" problem that was common with using the classpath.
Strong Encapsulation
In addition to resolving dependencies, the module system allows for strong encapsulation. This means that a module can hide its internal classes from other modules, exposing only what is necessary. This feature increases the security and integrity of the code, as it prevents the misuse of internal classes that are not intended for public use.
Compiling and Running Modules
To compile a module, you use the javac
compiler with the module-info.java
file. Once compiled, the module can be run with the java
tool, specifying the module name and the class containing the main
method.
Conclusion
The module system introduced in Java 9 is a significant advancement for the Java platform. It offers a better way to organize and manage code and dependencies, provides stronger encapsulation, and makes it easier to create lighter, more secure Java applications. While transitioning to the module system may require a learning curve and refactoring of existing code, the long-term benefits are significant for the Java community.
Because the module system is a profound change in the way Java is organized and executed, it is important for developers to become familiar with its concepts and tools. Migrating to the module system may be a gradual process, but it is an important step in ensuring that Java applications are sustainable and ready for future computing challenges.