Modularization is a long overdue feature of Java. It has been a major challenge, and the effort has taken many years.
The history of Java modularity
The first proposal for a module system was for Java SE 7 in 2005. This was postponed and planned for Java 8. This was delayed again because of the size and complexity. Eventually the Java SE platform was modularized in Java 9, which was released in September 2017.
The JSR 376: Java Platform Module System (JPMS) was the major enhancement in Java 9. It is also known as Project Jigsaw.
Project Jigsaw includes two JSRs (Java Specification Requests) and 7 JEPs (Java Enhancement Proposals).
What is a Module?
Think about modularity this way:
- A class is a container of fields and methods.
- A package is a container of classes and interfaces.
- A module is a container of packages.
Modules help us to encapsulate packages and manage dependencies between them. A module is simply a set of packages. It allows us to organise packages and control access to them. We can choose to expose only certain parts of the module, and hide others. We expose the parts of the module that we want to be reused, and we hide those parts that we don’t want to be reused.
Java 9 introduced a new set of language element related to modularity. The key new language element is the module.
A module is a named, reusable set of related packages, resources (such as images and XML files), native libraries and a module descriptor.
The module descriptor (module-info.java
) specifies:
- The name of the module.
- The module’s dependencies (the other modules on which this module depends).
- The packages it explicitly exposes to other modules. All other packages in the module are implicitly hidden.
- The services it provides.
- The services it uses.
- Which other modules can use the Reflection API to access elements in this module.
To control how its packages use other modules, a module declares which other modules it needs to compile and run the code in its packages.
To control how other modules use its packages, a module declares which of its packages are exported, and which are not. The next post will provide details on this.
Goals of Java Modularity
The main goals of JSR 376: Java Platform Module System included the following:
Scalable Java platform
Before Java 9, the Java platform library consisted of a huge number of packages. This was challenging to develop, modify and maintain. It wasn’t easy to create smaller subsets of the library. Java SE 8 introduced three compact profiles as subsets, but this was not entirely successful.
Now with Java 9, we can create custom runtime libraries that consist of only the modules we need. For example, if our application runs on a device that doesn’t have a GUI, we can create a smaller runtime library without the GUI modules.
Strong encapsulation
The packages in a module are accessible to other modules only if the module explicitly exports them. Another module cannot use those packages unless it explicitly states that it requires the other module’s capabilities. This improves platform security because fewer classes are accessible to potential attackers.
Reliable configuration
Modularity provides ways to explicitly declare dependencies between modules, both at compile time and run time.
Greater platform integrity
Before Java 9, it was possible to use internal APIs that were not really meant for general application use. These internal APIs are now properly encapsulated and hidden from general use. However, if legacy code depends on internal APIs, then migration to a modularized Java 9 can become a problem.
Improved performance
The JVM uses various optimization techniques to improve performance. These techniques are more effective knowing that required classes are located only in specific modules.
Listing Java Modules
As specified in JEP 200: The Modular JDK, the JDK has been divided into modules. This allows us to create custom runtime libraries.
We can list all the modules in our JDK by running the following from the command line:
java --list-modules
This command lists the set of observable modules available in the current JDK. Standard JSE specification modules have names starting with java
, such as java.base@11.0.6
. JDK specific modules have names starting with jdk
, , such as jdk.jartool@11.0.6
. Each module name has the JDK version after the @
character.
Additional modules could include JavaFX modules (names starting with javafx
), and vendor-specific modules (names starting with the vendor name, e.g.oracle
).
These modules can be seen in the \jmods
sub-directory of our JDK installation. Remember that with the Java versions before Java 9, the runtime libraries were in the \jre\lib
sub-directory of our JDK installation, with the main library JAR file being rt.jar
. Now the \jre\
directory no longer exists and has been replaced with the \jmods
directory .
What’s Next?
In the next post, we’ll look at some of the new contextual keywords relating to modules, and how to create a module.
Have you used Java modules? Don’t forget to share your comments.