Java Module System — Part II
This is a continuation of the module system introduced to Java 9 . You can find Part — I at the link below:
Nuances
The module system comes with its on set of rules on how it can be accessed. The module should be allowed to access the other module via the requires keyword. The other module should export the package and the type itself should be public (to make it visible)
The module system also requires that two modules cannot have the same package name. This enforcement separates the module-path from the class-path paradigm where packages could be overridden by multiple jars having same package name. This enforces stricter security on the classes being referred.
There are also performance optimization with respect to class loading as the JVM no longer needs to search the class-path but rather maps the package the module it needs to pick-up from
The module system also have set of other directives (apart from requires and export) for managing dependencies.
- transitive
There are cases where when module A depends on another module B, module A might also require to access types that are actually part of module B’s dependencies by virtue of its requires keyword. This is not possible out of the box as dependencies are not transitive.
Module A requires Module B requires Module C, doesn’t mean Module A automatically requires Module C
To make this happen we would need to use the transitive
keyword
module com.jtk.nutrition.lib {
requires transitive com.jtk.nutrition.loader;
requires transitive com.jtk.service;
}
The above declaration makes an module that requires com.jtk.nutrition.lib
to also have readability to modules com.jtk.nutrition.loader
and com.jtk.service
(a service module — more on that below). This way the top module (that requires com.nutrition.lib
) doesn’t have to require all the dependencies internally.
- aggregator
The above module in the application also acts as an aggregator, in that it doesn’t have to have any source except for the module-info.java.

In this way we can collate all the dependencies to a particular module and in the main module above ( com.jtk.nutrition.cli
) we just require the aggregator: com.jtk.nutrition.lib
Services
Java module system also introduces the concept of services. These are modules that only exposes the interfaces to the client. The actual implementations are separate modules that uses a special keyword to indicate a service implementation. As shown below our application is enhanced to include a service com.jtk.service
and its two implementations com.jtk.validate.number
and com.jtk.validate.string

The client
The module com.jtk.service
has the a single interface that is invoked by the clients. This invocation is made possible by the uses directive:
module com.jtk.nutrition.cli{
requires java.logging;
requires com.jtk.nutrition.lib;
uses com.jtk.service.api.ValidationService;
}
Unlike dependency injection where the implementation is injected at run-time, here the dependencies are looked up using ServiceLoader.load(ValidationService.class);
This returns a collection of implementations that can be called as such
Iterable<ValidationService> validationServices = ServiceLoader.load(ValidationService.class);
for (ValidationService s : validationServices) {
s.validate(o)
}
The problem with this is that, the client might need to call a particular implementation and there is no way to achieve this without having the interface expose a static factory method to retrieve the apt implementation (hidden behind the interface of-course! ). Again this is not dependency injection so you shouldn’t have the same expectations.
Also for reducing code duplicity, the above code needs to be part of the service interface; to that affect the uses
directive is moved to the service module as shown below:
module com.jtk.service {
exports com.jtk.service.api;
uses com.jtk.service.api.ValidationService;
}
And the interface exposes a factory method to select the implementation as below:
public interface ValidationService<T> {
boolean validate(T t);
boolean isSupportedType(Object t);
public static List<ValidationService> getValidators(Object item) {
List<ValidationService> validationServiceList = new ArrayList<>();
Iterable<ValidationService> validationServices = ServiceLoader.load(ValidationService.class);
for (ValidationService s : validationServices) {
if (s.isSupportedType(item))
validationServiceList.add(s);
}
return validationServiceList;
}
}
Now as the client doesn’t call the ServiceLoader directly and the client module com.jtk.nutrition.cli
doesn’t require the uses
directive
module com.jtk.nutrition.cli{
requires java.logging;
requires com.jtk.nutrition.lib;*(note)
}
*The com.jtk.nutrition.lib
module is an aggregator of the service and other modules required by the application (see aggregators above)
The implementation
On the implementation side of things i.e. com.jtk.validate.number
and com.jtk.validate.string
modules have a special directive that registers itself as services to an interface:
module com.jtk.validate.string {
requires com.jtk.service;
provides com.jtk.service.api.ValidationService with com.jtk.validate.string.FirstCapsValidator;
}module com.jtk.validate.number {
requires com.jtk.service;
provides com.jtk.service.api.ValidationService with com.jtk.validate.number.DoubleValidation;
}
The provides - with
keyword registers the implementations to the interface as above.
With that we have registered the implementation com.jtk.validate.string
and com.jtk.validate.number
to the service module com.jtk.service
and have provided a dependency to the client library via the aggregator com.jtk.nutrition.lib
as shown below

Summary
With this we have looked into the various rules regarding modules and how to handle aggregates and transitive dependencies. There are other directives but these are the essential ones to develop a robust modular system. We also looked into how services are created and how they are called with-in the module system.
In the next and final article on java modular system I intend to explore the jlink binary that comes with the module system in Java 9
Below is a reference to the source code for the above articles
References:
I have referred primarily the below book and also other websites in exploring the module system in java. Its a very good read!