Java 11 Developer Certification - Modules

May 13, 2021

What we are covering in this lesson

  1. Introduction
  2. Modular JDK
  3. Goals of modularizing the JDK
  4. Modular JDK - Java Standard Edition
  5. Modular JDK - Java Development Kit
  6. Modular SE Module Graph
  7. Examining modules from the command line
  8. Creating, Compiling and Running a module

Introduction

A module is a named set of packages, resources and native libraries. Java 9 introduces the concept of module, a new java entity that is similar to an executable jar in its production state, but that also includes a name and a descriptor class that provides certain benefits which never existed prior Java 9.

The benefits of a module are as follows;

  1. Stronger encapsulation at a higher level which improves security Prior to Java 9 any class in any package with a public or protected access modifier that was included in a jar on the classpath was by it’s nature publicly accessible or extensible by all of the application code. There was no way to hide this information.

In JDK 9, you have three ways to expose your public types - you can make them:

  • public to everyone, unqualified exposure.
  • public to just specific modules deemed friends, that’s qualified exposure.
  • not public to any other module, but only to the packages included in the module itself.

A module descriptor will specifically declare which packages are visible to other modules executing in the same application space.

  1. Reliable dependencies which improves stability A module descriptor requires a module to specifically declare which modules it’s dependent on, publishing it’s dependencies to consumers.

Modular JDK

Before Java 9, the JDK was a monolithic set of packages, packaged into one jar file, the rt.jar, which any java application would need to deploy along with it’s own code.

The Java platform has grown over time, to include about 25 different frameworks. Even if your application only used one class in a package, you’d need the rt.jar, which includes all of these frameworks.

Project Jigsaw was the name of the project created to modularize the JDK.

Goals of modularizing the JDK

The goals of modularizing the JDK was summarised by the Project Jigsaw team and restated here:

  • more scalability, by allowing the JDK to more easily scale down to smaller platforms.
  • improve security by protecting the internals of the JDK.
  • improved maintainability by publishing dependencies and reducing the amount of interdependencies.
  • improved application performance, by allowing configuration flexibility.
  • easier construction of and maintenance of libraries and large applications.

The Java designers spent a lot of time decoupling the frameworks and reconstructing the code into smaller sets of code, a few dozen modules, that met the objectives that we’ve just discussed. The smaller sets of code, nicely packaged into modular jar files, comprised the Modular JDK.

You can read in detail about modular JDK specifications here

The Modular JDK is split into two sections:

  • Java SE
  • JDK

Modular JDK - Java Standard Edition

The Java SE - The Java PLatform Standard Edition (Java SE) APIs.

  • These APIs define the core Java Platform for general-purpose computing.
  • These APIs are in modules whose names start with a ‘java.’ prefix.
  • All of the modules in the Java SE are standard modules as defined by the Java Community Process, JCP. However, not all standard modules defined by the JCP are in the Java SE, just the foundational standard modules.
  • A standard module may contain both standard and non-standard API packages.
  • A standard package is prefixed with ‘java.’ or ‘javax.’, such as java.lang and javax.net for example.

Modular JDK - Java Development Kit

The JDK - The Java Development Kit are specific to the JDK.

  • These APIs may not necessarily be available in all implementations of the Java SE Platform.
  • These APIs are in modules whose names start with ‘jdk.’ prefix.
  • Now these are non-standard modules.
  • A non-standard module must not export any standard API packages.
  • A non-standard package is generally prefixed with ‘jdk.’ such as jdk.internal.logger, for example.

Modular SE Module Graph

A module graph is a diagram, which attempts to visualise the module dependencies of a particular module.

If we look at the diagram here, the java.se module has dependencies on all of the modules shown, where as java.base has no dependencies, but is a required dependency for all the modules shown.

The arrows are called read edges - read because a module is said to be able to read another if properly configured as dependent on it.

For example, the java.xml module is said to read the java.base module. Note also that a module graph only displays module dependencies and will not include packages. You can read this in detail here

Each module shown is part of the Java API specification.

This link gives you all the information about the java.base module, and the packages and resources that it contains.

Remember that the java.base module is described as the foundational APIs of the Java SE Platform, which includes the core packages such as java.lang, java.util, java.io, etc.

Examining modules from the command line

We can run the below commands on the command line and can view the standard edition and JDK visible modules.

  • java —list-modules Shows the list of all available modules. Output is like below.
C:\Users\maxCode>java --list-modules
    java.base@11.0.7
    java.compiler@11.0.7
    java.datatransfer@11.0.7
    java.desktop@11.0.7
    java.instrument@11.0.7
    java.logging@11.0.7
    java.management@11.0.7
    java.management.rmi@11.0.7
    java.naming@11.0.7
    java.net.http@11.0.7
    java.prefs@11.0.7
    java.rmi@11.0.7
    java.scripting@11.0.7
    java.se@11.0.7
    java.security.jgss@11.0.7
    java.security.sasl@11.0.7
    java.smartcardio@11.0.7
    java.sql@11.0.7
    java.sql.rowset@11.0.7
    java.transaction.xa@11.0.7
    java.xml@11.0.7
    java.xml.crypto@11.0.7
    jdk.accessibility@11.0.7
    jdk.aot@11.0.7
    jdk.attach@11.0.7
    jdk.charsets@11.0.7
    jdk.compiler@11.0.7
    jdk.crypto.cryptoki@11.0.7
    jdk.crypto.ec@11.0.7
    jdk.crypto.mscapi@11.0.7
    jdk.dynalink@11.0.7
    jdk.editpad@11.0.7
    jdk.hotspot.agent@11.0.7
    jdk.httpserver@11.0.7
    jdk.internal.ed@11.0.7
    jdk.internal.jvmstat@11.0.7
    jdk.internal.le@11.0.7
    jdk.internal.opt@11.0.7
    jdk.internal.vm.ci@11.0.7
    jdk.internal.vm.compiler@11.0.7
    jdk.internal.vm.compiler.management@11.0.7
    jdk.jartool@11.0.7
    jdk.javadoc@11.0.7
    jdk.jcmd@11.0.7
    jdk.jconsole@11.0.7
    jdk.jdeps@11.0.7
    jdk.jdi@11.0.7
    jdk.jdwp.agent@11.0.7
    jdk.jfr@11.0.7
    jdk.jlink@11.0.7
    jdk.jshell@11.0.7
    jdk.jsobject@11.0.7
    jdk.jstatd@11.0.7
    jdk.localedata@11.0.7
    jdk.management@11.0.7
    jdk.management.agent@11.0.7
    jdk.management.jfr@11.0.7
    jdk.naming.dns@11.0.7
    jdk.naming.rmi@11.0.7
    jdk.net@11.0.7
    jdk.pack@11.0.7
    jdk.rmic@11.0.7
    jdk.scripting.nashorn@11.0.7
    jdk.scripting.nashorn.shell@11.0.7
    jdk.sctp@11.0.7
    jdk.security.auth@11.0.7
    jdk.security.jgss@11.0.7
    jdk.unsupported@11.0.7
    jdk.unsupported.desktop@11.0.7
    jdk.xml.dom@11.0.7
    jdk.zipfs@11.0.7
  • java —describe-module java.logging This command is used to examine a specific module, its version, its dependencies, and it’s published states. Output will be like below
C:\Users\maxCode>java --describe-module java.logging
    java.logging@11.0.7
    exports java.util.logging
    requires java.base mandated
    provides jdk.internal.logger.DefaultLoggerFinder with sun.util.logging.internal.LoggingProviderImpl
    contains sun.net.www.protocol.http.logging
    contains sun.util.logging.internal
    contains sun.util.logging.resources

Now you can also use the jdeps tool which is Java’s class dependency analyzer to also analyse modules. For example to view a quick summary of direct dependencies on a module you try this command

  • jdeps —print-module-deps -m java.sql

Output is the quick summary of the direct dependencies for the specifies module.

java.base,java.logging,java.transaction.xa,java.xml

-m OR —module can be used interchangeably.

Now as an alternative you can use another option like below.

C:\Users\maxCode>jdeps --list-reduced-deps --module java.sql
   java.base/jdk.internal.reflect
   java.logging
   java.transaction.xa
   java.xml

Now you can also get a listing which includes implied read edges, if there are any, and by using the list reduced deps you won’t see that. For this, we need to type in the below command

C:\Users\maxCode>jdeps --list-deps --module java.sql.rowset
   java.base/jdk.internal.reflect
   java.base/sun.reflect.misc
   java.logging
   java.naming
   java.sql
   java.xml

C:\Users\maxCode>jdeps --list-reduced-deps --module java.sql.rowset
   java.base/jdk.internal.reflect
   java.base/sun.reflect.misc
   java.naming
   java.sql

See the difference? —list-reduced-deps ignores java.logging and java.xml which are your implied read edges.

We will be discussing more of these commands in the next sections.

So till now, we have

  • discussed the goals of the Modular JDK as stated by project jigsaw.
  • introduced you to standard and non-standard modules.
  • introduced you to a module graph and showed you the Java SE module graph in action.
  • introduced you to some of the options that Java and the jdeps tools support for examining modules.

Creating, Compiling and Running a module

So when we create a module in IntelliJ, it automatically creates a src folder under that module. We will create a simple HelloWorld program within this src folder of module.

package maxCode.online.module;

public class HelloWorld {
	public static void main(String[] args) {
		System.out.println("Hello new modular world");
	}
}

Output

Hello new modular world

It looks very much the same as our normal class file. If we scroll the output, we can see a new argument -classpath. The fact that IntelliJ is still using this argument shows that we are still not using modules.

Now we will add a module-info.java file which will make the java class file run using this module

module MyFirstModule {

}

The module file can be as simple as module <moduleName> {}.

Now if we run the HelloWorld class, we get the same output but the arguments are different. Specifically we are no longer using the -classpath option, and it is replaced by -p (which can be replaced with —module-path), and a -m which is the alias for —module. So now we are executing our code as a module.

To run the same code from command line, we would type the below command on terminal (cmd)

java --module-path out\production\ -m MyFirstModule/maxCode.online.module.HelloWorld

To create a jar file for this module, we can run the below in terminal

jar --create --file MyFirstModule.jar --main-class maxCode.online.module.HelloWorld -C out\production\MyFirstModule\ .

This will create MyFirstModule.jar. You can examine the jar file as follows

jar -f MyFirstModule.jar --list

It will show all the files in the jar.

To describe the module, we can use -d.

Alternatively, we can also do the below

java --module-path . --describe-module MyFirstModule

To execute the code from the jar file

java --module-path . --module MyFirstModule

You can further try the jdeps command with this jar file and check the outputs.

That is all for this section, in the next part, we will create another module and see how to interact between modules.