Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

First steps with the Java 9 and Maven modules

Tags: module modules

First steps with the Java 9 and Maven modules – Jigsaw project, JSR 376

1. Introduction

The Jigsaw project ( JSR 376 – Java Platform Module System ), is born with the following objectives in mind:

  • Make the Java SE platform, and the JDK, can be broken down into smaller pieces to be used in small devices.
  • Improve the security and general maintenance of the Java SE platform implementations, and in particular of the JDK.
  • Enable the improvement of application performance.
  • Facilitate developers building and maintaining large libraries and applications, both for the Java SE and EE platform.

All this basically means that we will be able to break our application into pieces, which we will call modules , where each of these modules has its dependencies perfectly defined with other modules. And these dependencies are going to have a direct impact on the visibility of our classes.

Someone might think that we have already solved this with the JAR files and the dependency management of Maven (or Gradle ), but nothing else. Indeed, a JAR is a grouping of classes and with Maven we can define the dependencies both at the compilation and execution levels that these JARs have among them, but it has a big problem and that is that any class


is visible anywhere in the system, and this It goes against the basic principles of application design breaking with low coupling and high cohesion .

This happens because, for many JAR that we have, basically what Java does is load all the classes of all the JARs of our application in the same class loader , with which all the classes


are visible for the rest of the classes independently of the JAR or of the package in which they are defined.

At the level of Maven does not improve too much since we can express dependencies between JARs, for example

A → B

, but once this dependency is established, from


we can access all the classes


that are inB. For this reason, to improve the encapsulation it is usual to find names of packages of the style


where that


and that


are indicating us: beware! Beyond there are dragons! But it is simply that, a warning, because nothing prevents us from accessing the classes that are behind these “barriers”.

Even it is quite common to find libraries divided into several JARs (API and implementation) to ensure that, at least at the level of compilation, we do not access the classes that we do not owe (protection that will not exist at runtime). For example to get a dependency scheme with Maven similar to the initial drawing, we could do something like:

That is to say, practically every JAR we have to split it in two and specify the dependency in compilation with the API and in execution with the implementation. Also remember again that this will only affect us while compiling, but in runtime we can access any class, for example using reflection, so all this racking of JARs does not really guarantee the encapsulation of our classes.

2. Environment

The tutorial is written using the following environment:

  • Hardware: Notebook MacBook Pro 15 “(2.5 GHz Intel i7, 16GB 1600 Mhz DDR3, 500GB Flash Storage).
  • AMD Radeon R9 M370X
  • Operating System: macOS Sierra 10.12.4
  • Oracle Java 9-ea167
  • Maven 3.5.0

3. Definition of a module

We return here the graphic that we put at the beginning of the tutorial and that represents what we want to achieve in this example.

We see that we have a module


that depends on a service


and a module


. The dependencies to these two modules are the only direct ones that it has


, however in a transitive way it will also be able to access the module


. And in runtime you will access the module


that is the implementation of the service. The good thing about this is that the application does not really know who the service provider is, that is, we are getting control investment(not injection of dependencies).

To define a module we must add a file

in the root directory of our source code (in the directory where we would see our root package


). For example, in a Maven project it would be in the directory


  • By convention the root directory where the module code is located should have the name of the module itself, ie


    . For now we are going to skip this convention to maintain the


    and thus simplify the configuration of Maven.

For our simplest case, which is the moduleLogging, this file would look like this:

module com.autentia.logging {

exports com.autentia.logging;


We see how after the reserved word


comes the module ID , in our case it is


. This ID is in the form of a package name, but it is only a convention, since it is simply a string, so we could put what we wanted. When we want to refer to this module from another module, we will always use this ID.

Then between braces we see the definition of the modules. In this case we only see the reserved word


and then the name of the package that we want to expose outward. That is, from this module only the public classes that are in the package will be visible from other modules


. The rest of the public classes that are in the module but in other packages will be hidden both in compile time and in execution time.

4. Giving more visibility to the friendly modules

There are times where we can have several packages that are related. Among these packages we may want to export more classes than we expose to the rest of the world. So in our example we are going to assume that the module


wants to share with the module


certain classes that will not be visible to the rest of the world:

module com.autentia.words {

exports com.autentia.words;

exports com.autentia.words.friends to com.autentia.dictionary;


We see how we have a second


with a clause


. This indicates that the packet to the left of the


will only be visible by the module whose ID we have placed to the right of the


(important to emphasize that on the left we have put a package name while on the right we have put an ID of a module ). To the right of the


we can put a list of module IDs, separated by commas “,”.

5. Transitive dependence of a module

By default there are no transitive dependencies, that is, if our


module wants to use it


and it returns module classes in its public API


, the module


would be obliged to also declare the dependency with the module


. This does not seem practical or comfortable, since this double dependency (the module


and the module


) we would have to declare in all the other modules that want to use the module


To avoid this redundancy of having to always declare the module dependency,


it can be avoided by using the reserved word


. For example:

module com.autentia.dictionary {

exports com.autentia.dictionary;

requires transitive com.autentia.words;


Here, in line 5 we are indicating that everyone who requires the module as a dependency


, automatically transitively will also have the module classes available


6. Definition of a service

In our example we have already seen how we have a module from


which we are going to define a service, which is simply a


Java service. This service (interface) will be used in other parts of the system, but the funny thing is that you do not know who implements the service (interface). In this way we make our system easier to maintain since we can change the implementation of this service without touching a single line of code from the rest of the system.

To do this in the module


we saw that you simply exported a package. In this package is the interface that defines the service (this interface has nothing special, it is the implementation of a Java interface of a lifetime).

Now we are going to provide an implementation where the messages are simply written to the console. We will do this in the module


module com.autentia.logging.console {

requires com.autentia.logging;

provides com.autentia.logging.Logger with com.autentia.logging.console.ConsoleLogger;


Here on line 5 we can see how with the reserved word


we indicate the name of the interface (which is defined in the module


), and with the reserved word


we indicate the class, within the module


, that will implement this interface.

7. Location of a service

In point 3 we have seen how we define the service, and in point 6 we have seen how to indicate which class implements the service. Now we just need to locate this service to use it. So in the module


that represents our application we will declare:

module {

requires com.autentia.dictionary;
requires com.autentia.logging;

uses com.autentia.logging.Logger;


Here we highlight how in line 5 we use the reserved word


to indicate that in this module we are going to use the service. Note especially that in this module


we do not have any


to the module


but we simply have it to the module


that is where the interface is defined. In this way the code of our application is totally decoupled from the implementation of the service, since there is no dependency, neither in compilation nor in execution, between both modules.

The code of our application will look like this:

public class App {

private final Logger log = ServiceLoader.load(Logger.class).findFirst().get();
private final Dictionary dictionary = new Dictionary();

public static void main(String… args) {
new App().execute();

private void execute() {
final Word word1 = dictionary.getWord();
final Word word2 = dictionary.getWord();
final Word word3 = dictionary.getWord();



Where we see how on line 3 we are locating the service implementation without knowing what it is.

In the example we see how we locate the first implementation of the service with


, but here we could have all the logic we wanted, it would not even be complicated to change from a Service Locator pattern to a Dependency injection container .

8. And what about the old code? How do we migrate it to the module system?

When we try to load a class that is not found in any module, it will be searched in the normal Java class path (the class path of all life). If it is in the class path, this class is automatically added to a special module called “module without name” ( unnamed module ). In this way, this unnamed module will contain all the classes that are not explicitly defined in any module.

The unnamed module can access all the public classes that are exported in the rest of the named modules (explicit modules). On the contrary, the named modules can not access any class that is in the module without a name, in fact you can not even specify a dependency to the unnamed module. This restriction is set on purpose to force the developers to make a correct configuration of the modules.

All this allows us to make a gradual migration of our applications, since the new modules with JAR that do not yet have defined modules can coexist perfectly.

Taking into account the aforementioned restrictions, we will have to do this migration from bottom to top . That is a dependency graph would begin to migrate leaves (JARs that do not depend on others, in our example would be


…), and we’d go up in the dependency graph (in our example would end by the module



The problem with this migration from the bottom up is that we can touch our code, but we will always depend on third parties that, if they are not migrated to the new module system, can not be accessed from our modules. In these cases what we can do is treat these JARs as an “automatic module” ( automatic module ), simply by placing the JAR in the module pathinstead of the class path . In this way a module is generated implicitly, where its name will be determined by the name of the file. And so we can use it as if it were any other module with a name.

10. Conclusions

The Java 9 modules are presented as a powerful tool for encapsulation. We have seen how we can declare dependencies, do these transitive, define implement and use services, …

However, what about Maven / Gradle? In the complete example of code you can see how both can coexist today, there being a small duplication of concepts, since we are forced to define the dependencies in two points: Java 9 modules and Maven modules for compilation . We will see if in later versions of Maven this information is read directly from the Java 9 modules, or is it time for a new packaging system?

And if we can define and inject services, what about Spring? Is it his end? Will there be a link between the two? Of course there will be movement because with the new restrictions that the module path Spring imposes, it will not be so easy to do its “automagies”.

In general there are many uncertainties (for example, as we have said before, migrations from the bottom up are not going to be simple because it implies that everyone has to do it), and in fact there are a few detractors, for example here you have a good Concerns Regarding Jigsaw article (JSR-376, Java Platform Module System) . Eye that is long, but it is worth to see the corners that still remain to be polished.

With all this, what remains is to study, practice and observe where things are moving, to see if the Java 9 modules are finally imposed or, on the contrary, they continue to opt for third-party solutions such as OSGi , which on the other hand are much more powerful.

The post First steps with the Java 9 and Maven modules appeared first on Target Veb.

This post first appeared on Targetveb, please read the originial post: here

Share the post

First steps with the Java 9 and Maven modules


Subscribe to Targetveb

Get updates delivered right to your inbox!

Thank you for your subscription