The main innovation in Java 9 was the introduction of modules. There was a lot of talk about this feature, the release date was postponed several times to finish everything properly. Today we’ll talk about the mechanism of modules, and what benefits Java 9 brought in general. The post is based on the report of Sergei Malkevich, developer. IntexSoft Java Project Jigsaw To implement the modules in this version of Java, a whole new project was allocated — Project Jigsaw — which includes several JEPs and JSRs. For those who like the official documentation, you can learn more about each JEP. here Project Jigsaw started back in 2005: first, JSR 277 was released, and then in 2008 the actual work on the project began. It was released only in 2017. So it took almost 10 years to finish the Java modules in a proper way. Which, in fact, emphasizes the full scale of work and changes that were made during the implementation of modules. Project goals: facilitate the development of large applications and libraries; improve the security of Java SE in general, and JDK in particular; improve application performance; enable the Java SE and JDK to scale down for use in small devices in order not to consume too much memory; JAR HELL. Java 9 Updates Prior to version 9, . Their size grew with each release. Java 8 already occupied hundreds of Mb, and the developers had to “carry all this stuff” each time in order to run Java applications. Only alone takes about 60 Mb. Well, here we can also add a slow start and high memory consumption. So, Java 9 can help here. JDK and JRE were monolithic rt.jar introduced the module system, namely, the JDK was divided into 73 modules. And each new version brings us a higher amount of these modules. In the 11 version, this number is close to 100. This separation allows developers to create the tool to create custom JRE that will include only those modules the application really needs. Thus, a simple application and some custom JRE with a minimal (or a small) set of modules can eventually fit in 20 Mb, which is good news. JDK 9 Jlink You can check the list of modules . here With Java 9, the JDK structure has changed: now it is identical to the JRE structure. If earlier the JDK included the JRE folder with bin and duplicate files, now everything looks as follows: Modules What is a module, actually? A module is a new level of packages and resources aggregation, or as developers say: . ...a uniquely named, reusable group of related packages, as well as resources and a module descriptor Modules are delivered in JAR files with packages and a module descriptor — module-info.java. The file contains: name, dependencies, public packages, consumed and offered services, reflection permissions. module-info.java Examples of module descriptor: java.sql { transitive java.logging; transitive java.transaction.xa; transitive java.xml; java.sql; javax.sql; uses java.sql.Driver; } module requires requires requires exports exports jdk.javadoc { java.xml; transitive java.compiler; transitive jdk.compiler; jdk.javadoc.doclet; provides java.util.spi.ToolProvider with jdk.javadoc.internal.tool.JavadocToolProvider; provides javax.tools.DocumentationTool with jdk.javadoc.internal.api.JavadocTool; provides javax.tools.Tool with jdk.javadoc.internal.api.JavadocTool; } module requires requires requires exports First is the keyword, followed by the name of the package, which depends on another package and is transitively dependent on other packages. module jdk.javadoc java.xml Let’s take a closer look at the keywords: specifies the modules the current module depends on; requires specifies the transitive dependency: if the module is transitively dependent on the module , and we have some third module , which depends on , then the module requires transitive m1 m2 mX m1 mX will also have access to m2; specifies the compile-time-only dependencies; requires static specifies the packages of the module that should be accessible for other modules (not including “sub-packages”); exports allows us to restrict the access: ; that is, we can open access to the package of our module only for some other(s) package(s) of another module; exports…to… export com.my.package.name to com.specific.package specifies the services used by the module: uses uses java.sql.Driver; In this case, we specify the interface of the service used. specifies the services provided by the module: provides provides javax.tools.Tool with jdk.javadoc.internal.api.JavadocTool; First we put the interface — , and after — the implementation. javax.tools.Tool with A little more about services Let’s say we have several modules connected which implement an abstract service — . When assembling the application, we can decide what service implementation to use by dropping the desired service implementation modules to : MyService --module-path Iterable <MyService> services = ServiceLoader.load(MyService.class); Thus, the returned contains a list of implementations of the interface. In fact, it will contain all the implementations found in the modules on . Iterator MyService --module-path Why services were introduced at all? They are needed to show how our code will be used. So it’s all about a semantic role. Also, modularity is about encapsulation and security, as we can make the implementation and exclude the possibility of unauthorized reflection access. private One more option of using services is a rather simple implementation of plugins. We can implement the plugin interface for our application and connect modules to work with them. Let’s go back to declarations Before Java 9 it was possible to use reflection to access almost everything, and we could do whatever we want. But as already mentioned, version 9 allows us to protect our app from “illegal” reflection access. We can allow full reflection access to the module by declaring : open open my. { } module module Or, we can expose specific packages with : opens my. { opens com.my.coolpackage; } module module It is also possible to use , thus opening the specific packages to the specific module(s). opens…to Module Types Project Jigsaw classifies modules as follows: — Java SE and JDK modules. You can find the complete list using the java command. System Modules --list-modules — the modules of our app written by us, and also the dependencies (from third-party libraries) that our application uses. Application Modules — these are modules with open access created automatically by Java from JAR files. Let’s say we want to run our application in a modular mode, but it uses some library. In this case, we put the JAR file on and Java automatically creates a module with the name inherited from the name of the JAR file. Automatic Modules --module-path — an unnamed module automatically generated from all JAR files loaded to . This is a catch-all module for backward compatibility with previously written Java code. Unnamed Module --class-path Class-path vs module-path With modules, a new concept appeared — . In fact, this is the classpath we all know, but for modules. module-path Starting a modular application looks like this: In a “classic mode”, we specify options and the full path to the main class. If we want to work with modules, we also specify or parameter, which indicates that we will run modules. That is, we automatically put our application in a “modular mode”. Then, we specify the module name and the path to the main class from the module. -m -module Also, in addition to classic and parameters we are used to working with, we add new and parameters, which indicate the paths to the modules used in the app. -cp --class-path -p --module-path It often happens that developers do not switch to Java 9+ because they believe they will have to work with modules. Although in fact, we can run our applications without adding a parameter for modules and use only other new features of Java 9. JAR HELL What is Jar Hell in a nutshell? For example, our application depends on Library and Library . Moreover, both of these libraries depend on Library , but on different versions: depends on , and depends on . X Y Z X version 1 Y version 2 It’s okay if is backward compatible with , we’ll have no problem then. But if not, obviously, we’ll have a versions conflict, which means the same library cannot be loaded into memory by the same class loader. version 2 version 1 How do developers get over such situations? There are standard methods that developers have been using since the very first Java, for example: exclude, or plugins for Maven, which rename the root packages of the library. Or sometimes developers are looking for different versions of Library X to find a compatible option. In fact, the very first Jigsaw prototypes supposed the module might have a version and allowed different versions to be downloaded by different ClassLoaders. Later that idea was removed. As a result, the “silver bullet” many of us were waiting for did not work out. But still, the developers secured us from such problems right out of the box. In , Split Packages are forbidden. These are the packages divided into several modules. That is, if we have the in one module, we cannot use it in another module within the same app. Java 9 com.my.coolpackage If we run the application with modules containing the same packages, we’ll simply crash. This small improvement eliminates the possibility of unpredictable behavior connected with Split Packages downloading. In addition to the modules themselves, there is a Jigsaw Layers mechanism, which also helps to cope with the Jar Hell. A Jigsaw layer can be defined as some local module system. Here it is worth noting that the Split packages mentioned above are prohibited only within one Jigsaw layer. Modules with the same packages have a place to be, but they must belong to different layers. It looks like this: When the application starts, a Boot layer is created, which includes platform modules loaded by Bootstrap, additional platform modules loaded by the Extension loader, and modules of our application loaded by the Application loader. We can create our own layers anytime and “put” modules of different versions there without any problems. Here is a detailed presentation by Nikita Lipsky to learn more about the subject: Escaping The Jar Hell With Jigsaw Layers To sum up The modules from Java 9 open up new possibilities for us, while the support for libraries today is quite limited. Of course, people run Spring, Spring Boot, and so on. But most libraries have not switched to the full use of modules. Apparently, that’s why all these changes were met rather skeptically by the tech community. Modules provide us with new opportunities, but the demand issue remains open. And finally, here is a list of useful content to learn: Project Jigsaw JDK Module Summary Paul Deitel — Understanding Java 9 Modules baeldung.com — Introduction to Project Jigsaw Alex Buckley — Modular Development with JDK 9 Previously published at https://intexsoft.com/