Chapter 1. Understanding Modules

1.1.  Describe the Modular JDK


JDK was divided into a set of modules that can be combined at compile time, build time, and run time into a variety of configurations including, but not limited to:

  • Configurations corresponding to the full Java SE Platform, the full JRE, and the full JDK;

  • Configurations roughly equivalent in content to each of the Compact Profiles defined in Java SE 8; and

  • Custom configurations which contain only a specified set of modules possibly augmented by external library and application modules, and the modules transitively required by all of these modules.

The definition of the modular structure should make a clear distinction between standard modules, whose specifications are governed by the Java Community Process, and modules that are specific to the JDK. It should also distinguish modules that are included in the Java SE Platform Specification, and thereby made mandatory in every Platform Implementation, from all other modules.

Project Jigsaw aims to design and implement a standard module system for the Java SE Platform and to apply that system to the Platform itself, and to the JDK. Its primary goals are to make implementations of the Platform more easily scalable down to small devices, improve security and maintainability, enable improved application performance, and provide developers with better tools for programming in the large.

The modular structure of the JDK implements the following principles:

  1. Standard modules, whose specifications are governed by the JCP, have names starting with the string "java.".

  2. All other modules are merely part of the JDK, and have names starting with the string "jdk.".

  3. If a module exports a package that contains a type that contains a public or protected member that, in turn, refers to a type from some other module, then the first module must grant implied readability to the second, via requires transitive. (This ensures that method-invocation chaining works in the obvious way.)

  4. A standard module may contain both standard and non-standard API packages. If a standard module exports a standard API package then the export may be qualified; if a standard module exports a non-standard API package then the export must be qualified. In either case, if a standard module exports a package with qualification then the export must be to some subset of the modules in the JDK. If a standard module is a Java SE module, i.e., is included in the Java SE Platform Specification, then it must not export any non-SE API packages, at least not without qualification.

  5. A standard module may depend upon one or more non-standard modules. It must not grant implied readability to any non-standard module. If it is a Java SE module then it must not grant implied readability to any non-SE module.

  6. A non-standard module must not export any standard API packages. A non-standard module may grant implied readability to a standard module.

An important consequence of principles 4 and 5 is that code that depends only upon Java SE modules will depend only upon standard Java SE types, and thus be portable to all Implementations of the Java SE Platform.

The module list

You can list all JDK modules by running this command:

java --list-modules

List of Java 11 modules is shown below:


The module graph

The modular structure of the JDK can be visualized as a graph: Each module is a node, and there is a directed edge from one module to another if the first depends upon the second. The full module graph has too many edges to be displayed easily.

Here is the Java SE 11 Module Graph.

Please take a look at appendix for the instruction how you can re-create it: “How to build JDK module graph”

Herewith a guided tour of the Java 11 module graph:

  • Standard Java SE modules (java.) are colored Cyan; non-SE modules (jdk.) are colored Dark Sea Green.

  • If one module depends upon another, then there is an edge from the first module to the second.

  • At the very bottom is the java.base module, which contains essential classes such as java.lang.Object and java.lang.String. The base module depends upon no module, and every other module depends upon the base module.

  • Near the top is the module, which gathers together all of the modules that comprise the Java SE Platform. This is an example of an aggregator module, which collects and re-exports the content of other modules but adds no content of its own. A run-time system configured to contain the module will contain all of the API packages of the Java SE Platform. A module is included in the Java SE Platform Specification if, and only if, it is a standard module reachable from the module.

  • The non-standard modules (jdk.) include debugging and serviceability tools and APIs, development tools, and various service providers, which are made available to other modules via the existing java.util.ServiceLoader mechanism.

  • The java.smartcardio module is standard but not part of the Java SE Platform Specification, hence its name starts with the string "java." but it is not reachable from the module.

Using jlink to build Java Runtime Environments

Since Java 9 the Java Platform Module System (JPMS) has divided the monolithic rt.jar and tools.jar files into more than 70 distinct modules.

As of JDK 9 also eliminated the distinction between the Java Development Kit (JDK) and the Java Runtime Environment (JRE). In the past, there was a sub-directory in the JDK called jre which only contained things that were required to run a Java application.

In JDK 9 and later, the idea is to build Java Runtime Environments that are tailored to the requirements of a specific application. Rather than including all modules, you need only include the java.base module (which all runtimes must include by definition) as well as any other modules the application references. All transitive module dependencies must also be included. JDK 9 and later provides the jlink command to assemble and optimize a set of modules and their dependencies into a custom runtime image.

Let's create a sample modular application, as shown below:


module MOD {    

package app;

public class App {
    public static void main(String[] args) {
        System.out.println("Hello jlink !");

To run this program, we only need App, String, System, and Object classes.

With help of jlink command line utility we can create our own small JRE that contains only the relevant classes and packages that application needs to use, without wasting memory and disk space.

Let's compile the code:

C:\1Z0-817-jlink>javac -p . app/

│   module-info.class

Now, create the modular JAR:

C:\1Z0-817-jlink>jar cf app.jar -C . .

In order to use jlink, we need to know the list of the Java SE modules that the application uses and that we should include in our custom JRE. Let's use the jdeps command to list the modules used in the application:

C:\1Z0-817-jlink>jdeps --list-deps app.jar

To create a custom JRE for a module based application we use the jlink command:

C:\1Z0-817-jlink>jlink --add-modules java.base --output java-runtime

The comma separated list of modules after the -–add-modules option tells jlink which modules to include in the new JRE.

The -–output option defines the target directory where our custom JRE should be generated.

The size of custom JRE (created with Java 11) is about 39 Mbytes:

C:\1Z0-817-jlink\java-runtime>dir /s
     Total Files Listed:
              91 File(s)     41,226,208 bytes

To test our new JRE, let's try to run our module by navigating inside the bin folder of our java-runtime directory and run the command:

C:\1Z0-817-jlink\java-runtime\bin>java.exe -p ../../app.jar --module MOD/app.App
Hello jlink !

You can also create a custom JRE with executable launcher scripts (for Windows and Linux). For this, you need to run the jlink command that has an extra -–launcher option to create launcher with the application module and main class (NOTE: delete old custom JRE before creating new):

C:\1Z0-817-jlink>jlink -p ./app.jar --add-modules java.base,MOD --output java-runtime --launcher app=MOD/app.App

C:\1Z0-817-jlink\java-runtime\bin>dir app*
  Directory of C:\1Z0-817-jlink\java-runtime\bin

05/25/2019  00:45                91 app
05/25/2019  00:45               100 app.bat
               2 File(s)            191 bytes

Generated app.bat:

@echo off
set DIR=%~dp0
"%DIR%\java" %JLINK_VM_OPTIONS% -m MOD/app.App %*

Run the script:

Hello jlink !

Professional hosting         Exam 1Z0-817: Upgrade OCP Java 6, 7 & 8 to Java SE 11 Developer Quiz     Exam 1Z0-810: Upgrade to Java SE 8 Programmer Quiz