Java 9 Modules Tutorial – Getting Started

Learn how to start using modules in java 9 – a beginner tutorial.

“A man who dares to waste one hour of time has not discovered the value of life.” ― Charles Darwin, The Life & Letters of Charles Darwin

1. Introduction

A major enhancement of Java version 9 is the Modules facility. Modules have been designed to be especially useful in building and maintaining large systems.

2. What is a module?

A module is a declaration associated with a package that specifies meta information about the package such as:

  • Names of other modules that the package depends on.
  • Classes and types within the package that other modules can depend on.

3. What are some of the key advantages of modules?

  • Declare Dependencies: Modules allow you to declare dependencies between modules. For instance, moduleA can declare a dependency on moduleB.
  • Improved Encapsulation: Classes can only use classes from other modules that have been explicitly exported. If a module designer, does not declare a class as exported, you cannot use it from outside the module.
  • Runtime Customization: The Java SDK has been divided into 95 modules (at present). If your application does not need or use some modules, you can build a runtime which does not include those modules, thus reducing the size of the runtime.
  • Better Isolation: Previously, there was no way to protect internal APIs from use by outside modules. The outside module is better protected from unexpected changes to the API if it does not use such internal modules.
  • Performance Improvements: The JVM can better optimize an application if it knows in advance where the required types are located.

Let us now get our hands wet and explore the module system with a simple program.

4. Setup Maven

When using maven to compile your application, you need to tell the compiler plugin of the java version as follows:

<project xmlns="http://maven.apache.org/POM/4.0.0"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                 http://maven.apache.org/maven-v4_0_0.xsd">

  ..

  <properties>
    <javac.target>1.9</javac.target>
  </properties>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.1</version>
        <configuration>
          <compilerVersion>${javac.target}</compilerVersion>
          <source>${javac.target}</source>
          <target>${javac.target}</target>
      <compilerArgument>-Xlint</compilerArgument>
        </configuration>
      </plugin>
      ..
</project>

You also need to set JAVA_HOME in your environment.

export JAVA_HOME=/usr/lib/jvm/jdk-9.0.4

With these changes, maven should be able to build your application using java 9.

5. Standard Modules

The Java platform has now been divided into many modules (currently, 28 modules in java, 8 modules in javafx, 61 modules in jdk and 2 modules in oracle), which you can find out by running:

java --list-modules
# prints
java.activation@9.0.4
java.base@9.0.4
java.compiler@9.0.4
java.corba@9.0.4
java.datatransfer@9.0.4
java.desktop@9.0.4
java.instrument@9.0.4
java.jnlp@9.0.4
java.logging@9.0.4
java.management@9.0.4
java.management.rmi@9.0.4
java.naming@9.0.4
java.prefs@9.0.4
java.rmi@9.0.4
java.scripting@9.0.4
java.se@9.0.4
java.se.ee@9.0.4
java.security.jgss@9.0.4
java.security.sasl@9.0.4
java.smartcardio@9.0.4
java.sql@9.0.4
java.sql.rowset@9.0.4
java.transaction@9.0.4
java.xml@9.0.4
java.xml.bind@9.0.4
java.xml.crypto@9.0.4
java.xml.ws@9.0.4
java.xml.ws.annotation@9.0.4
javafx.base@9.0.4
javafx.controls@9.0.4
javafx.deploy@9.0.4
javafx.fxml@9.0.4
javafx.graphics@9.0.4
javafx.media@9.0.4
javafx.swing@9.0.4
javafx.web@9.0.4
jdk.accessibility@9.0.4
jdk.aot@9.0.4
jdk.attach@9.0.4
jdk.charsets@9.0.4
jdk.compiler@9.0.4
jdk.crypto.cryptoki@9.0.4
jdk.crypto.ec@9.0.4
jdk.deploy@9.0.4
jdk.deploy.controlpanel@9.0.4
jdk.dynalink@9.0.4
jdk.editpad@9.0.4
jdk.hotspot.agent@9.0.4
jdk.httpserver@9.0.4
jdk.incubator.httpclient@9.0.4
jdk.internal.ed@9.0.4
jdk.internal.jvmstat@9.0.4
jdk.internal.le@9.0.4
jdk.internal.opt@9.0.4
jdk.internal.vm.ci@9.0.4
jdk.internal.vm.compiler@9.0.4
jdk.jartool@9.0.4
jdk.javadoc@9.0.4
jdk.javaws@9.0.4
jdk.jcmd@9.0.4
jdk.jconsole@9.0.4
jdk.jdeps@9.0.4
jdk.jdi@9.0.4
jdk.jdwp.agent@9.0.4
jdk.jfr@9.0.4
jdk.jlink@9.0.4
jdk.jshell@9.0.4
jdk.jsobject@9.0.4
jdk.jstatd@9.0.4
jdk.localedata@9.0.4
jdk.management@9.0.4
jdk.management.agent@9.0.4
jdk.management.cmm@9.0.4
jdk.management.jfr@9.0.4
jdk.management.resource@9.0.4
jdk.naming.dns@9.0.4
jdk.naming.rmi@9.0.4
jdk.net@9.0.4
jdk.pack@9.0.4
jdk.packager@9.0.4
jdk.packager.services@9.0.4
jdk.plugin@9.0.4
jdk.plugin.dom@9.0.4
jdk.plugin.server@9.0.4
jdk.policytool@9.0.4
jdk.rmic@9.0.4
jdk.scripting.nashorn@9.0.4
jdk.scripting.nashorn.shell@9.0.4
jdk.sctp@9.0.4
jdk.security.auth@9.0.4
jdk.security.jgss@9.0.4
jdk.snmp@9.0.4
jdk.unsupported@9.0.4
jdk.xml.bind@9.0.4
jdk.xml.dom@9.0.4
jdk.xml.ws@9.0.4
jdk.zipfs@9.0.4
oracle.desktop@9.0.4
oracle.net@9.0.4

6. Sample Java Code

Here is a sample program to illustrate the use of modules in java 9. The program writes a Hello World message to the console, and also uses the Java Logging Framework to log a message. We have used java logging to illustrate the use of a module other than java.base. Java Logging Framework is used by requiring the module java.logging.

package sample;

import java.util.logging.Logger;

public class sample1
{
    static private Logger Log = Logger.getLogger("sample");

    static public void main(String[] args) throws Exception
    {
        System.out.println("Hello World!");
        Log.info("A hello world log message");
    }
}

7. Module Information

The information about modules must be stored in a file called module-info.java at the top of the directory where the package tree starts from. For our example, the folder structure looks like this:

We have started out with a simple **module-info.java*. Let us see if we can get this working.

module joe {
}

8. Compiling the Application

Let us now compile the program.

mvn clean package

You end up with this error.

[ERROR] (package java.util.logging is declared in module java.logging, but module joe does not read it)

And there you have it. The compiler tells you what is wrong: you need to declare java.logging as a dependency. Let us make that change, and for good measure, let us also add java.base just to be explicit.

module-info.java:

module joe {
    requires java.base;
    requires java.logging;
}

Compiling the project now does not result in any errors.

9. Running the Application

You can of course run the program in the way you have been accustomed to.

java -cp target/sample-0.1.0-SNAPSHOT.jar sample.sample1
# prints
Hello World!
Mar 13, 2018 9:41:33 AM sample.sample1 main
INFO: A hello world log message

This method of executing the program is still supported for backward compatibility, and does not really use the module information. Just like before, everything is exposed everywhere.

Let us try to run it as a module. Here is how you do it.

java -p target/sample-0.1.0-SNAPSHOT.jar -m joe/sample.sample1
# prints
Hello World!
Mar 13, 2018 9:43:43 AM sample.sample1 main
INFO: A hello world log message

You tell the JVM where to find the modules using the -p option. The argument can be a path where module-info.class is present. Or it can be a JAR file which contains module-info.class and the root level as shown here.

jar tf target/sample-0.1.0-SNAPSHOT.jar
# prints
META-INF/
META-INF/MANIFEST.MF
sample/
module-info.class
sample/sample1.class
META-INF/maven/
META-INF/maven/sample/
META-INF/maven/sample/sample/
META-INF/maven/sample/sample/pom.xml
META-INF/maven/sample/sample/pom.properties

The -m option specifies the module and the class name to run.

Conclusion

In this tutorial, we looked at java 9 modules feature, and learnt how to begin using it in projects. We explored the use of a single directive requires to declare dependencies. In future articles, we will cover more of the module directives.