A module is a group of closely related Java packages and resources along with a new module descriptor file.
A module is distributed as a regular jar file.
Each module is responsible for its resources, like media or configuration files.
Previously, we put all resources into the root level of our project.
We manually manage which resources belong to different parts of the application.
It works, but it is not really a good way to define modular systems.
With modules, we can ship required images and XML files with the module that needs it, making our projects much easier to manage.
Module Descriptor
When we create a module, we include a descriptor file that defines several aspects of our new module:
- Name
-
the name of our module.
Please use the same conventions as for package names.
- Dependencies
-
a list of other modules that this module depends on.
- Public Packages
-
a list of all packages we want accessible from outside the module.
- Services Offered
-
we can provide service implementations that can be consumed by other modules.
- Services Consumed
-
allows the current module to be a consumer of a service.
- Reflection Permissions
-
explicitly allows other classes to use reflection to access the private members of a package.
Please minimize the use of reflection.
The module naming rules should be similar to how we name packages.
It is common to do Reverse-DNS net.tangly.mymodule style names.
Module Directives
We need to list all packages we want to be public because by default, all packages are module private.
- Used Dependencies
-
We can declare dependencies on other modules.
- requires module list
-
depends on the named module
- requires static module list
-
depends on the named module, but that users of our library will never want to use.
- requires transitive module list
-
depends on the named module and makes it available to users of our module.
- Provided Abstractions
-
By default, a module does not expose any of its API to other modules.
- exports package list
-
We use the exports directive to expose all public members of the named package.
The export quantum is a package, not a class or interface.
- exports package list to module list
-
Similar to the exports directive, we declare a package as exported.
We additionally list which modules we are allowing to import this package as required.
This mechanism is similar to the friend concept in C++.
- Services
-
A service is an implementation of a specific interface or abstract class that can be consumed by other classes.
- uses classname
-
We designate the services our module consumes with this directive.
- provides service name with class list
-
A module can also be a service provider that other modules can consume.
The first part of the directive is the provides keyword.
Here is where we put the interface or abstract class name.
Next, we have the with directive where we provide the implementation class name that either implements the interface or extends the abstract class.
- Reflection
-
- open
-
If we want to continue to allow full reflection as older versions of Java did, we can simply open the entire module up to reflection.
- opens package list
-
If we need to allow reflection of private types, but we do not want all of our code exposed, we can use the opens directive to expose specific packages.
But remember, this will open the package up to the entire world, so be careful with this directive.
- opens package list to module list
-
We can selectively open our packages to a pre-approved list of modules, in this case, using the opens…to directive.
module net.tangly.fsm {
exports net.tangly.fsm;
exports net.tangly.fsm.dsl;
exports net.tangly.fsm.utilities;
requires org.apache.logging.log4j;
requires static transitive org.jetbrains.annotations;
}
Module Types
There are four types of modules in the new module system:
- System Modules
-
These are the modules listed when we run the list-modules command above.
They include the Java SE and JDK modules.
- Application Modules
-
These modules are what we usually want to build when we decide to use Modules.
They are named and defined in the compiled module-info.class file included in the assembled JAR.
- Automatic Modules
-
We can include unofficial modules by adding existing JAR files to the module path.
The name of the module will be derived from the name of the JAR.
Automatic modules will have full read access to every other module loaded by the path.
- Unnamed Module
-
When a class or JAR is loaded onto the classpath, but not the module path, it is automatically added to the unnamed module.
It is a catch-all module to maintain backward compatibility with previously written Java code.