Java Modularity Part 7 – Compiling Modules

Java modularity

In this final installment on modules, we’ll look at a simple example of compiling and packaging a module.

If you missed the previous posts in this sequence, you can find them here:

Java Modularity Example

Let’s use the standard “Hello, world!” code that’s been used a million times before. In this example however, we’ll modularize it.

package com.incusdata.test;

public class ModularHelloWorld {

   public static void main (String args[]) {
   System.out.println("Hello, modular world!");
   }
} // end of class

Directory structure

There’s nothing exotic or new about the Java code. What does change, however, is the directory structure where we place the code. We would have previously stored the ModularHelloWorld.java file under a directory hierarchy with the same names as the package name, as in com\incusdata\test\ModularHelloWorld.java.

Let’s assume that we would like to create a module called com.incusdata.test. Following a common module naming convention, our package directory structure would now placed under a directory with the same name as the module, hence com.incusdata.test\com\incusdata\test\ModularHelloWorld.java.

We would also create a module-info.java file in the com.incusdata.test directory.

For the example, our full directory structure is the following:

src
|_ com.incusdata.test - module-info.java
    |_ com
        |incusdata
           |_ test - ModularHelloWorld.java
mods
target

The src directory will be used for our source code. The mods directory will be used for the compiled modules and classes. The target directory will be used for the resulting JAR file.

The contents of the module-info.java is as follows.

module com.incusdata.test {
   requires java.base;
}

We’ve already seen modules in some of the previous posts. Within the module, we need to define the Java modules we require. In this case, we only require the java.base module. We added it for clarity, rather than necessity because it is always implicitly added.

Compiling the code

For this example, we’ll be compiling from the command line. By doing this, we get a better understanding of how things work.

javac -d mods/com.incusdata.test
      src/com.incusdata.test/module-info.java                                                src/com.incusdata.test/com/incusdata/test/ModularHelloWorld.java

The -d option specifies the destination directory for the compiled classes. We compile it to a directory – com.incusdata.test – which has the same name as our module.

Running the program

To run the compiled program, we need to set the --module-path. This command-line option sets the directories where the modules can be found. The --module option sets the main class that is called.

java --module-path mods 
     --module com.incusdata.test/com.incusdata.test.ModularHelloWorld

The output will be Hello, modular world! as we would expect.

Creating a JAR file

When we create a module, we’d generally like to package it as a JAR file for easy distribution.

The command to do this is the following:

jar --create --file target/test-modular-helloworld.jar 
    --main-class com.incusdata.test.ModularHelloWorld
    -C mods/com.incusdata.test 

The target directory must exist before running the jar command. The --file option specifies the JAR file name and directory. The --main-class obviously specifies the main class or entry point. The (uppercase) -C option specifies the files to include in the JAR file.

We can execute the application for the JAR file with the following command:

java --module-path target/test-modular-helloworld.jar 
     --module com.incusdata.test/com.incusdata.test.ModularHelloWorld

To check on the module description, we can use the --describe-module option as follows:

java --module-path target/test-modular-helloworld.jar
     --describe-module com.incusdata.test

Importing a package

The previous example was very simple, but in a real-world application, we would want to import packages for other modules as well. Let’s import a constant, say java.awt.BorderLayout.NORTH and print it out:

package com.incusdata.test;

import static java.awt.BorderLayout.NORTH;

public class ModularHelloWorld {

   public static void main (String args[]) {
       System.out.println("Hello, modular world!");
       System.out.println("java.awt.BorderLayout.NORTH: " + NORTH);
   }
} // end of class

If we compile it as before, the compilation fails. This is because we didn’t import the java.desktop module which includes the java.awt package. We need to change the module-info.java to require the java.desktop module:

module com.incusdata.test {
   requires java.base;
   requires java.desktop;
   requires java.xml;
}

Compiling, packaging and running it as before will give us the correct output.

What’s Next?

I’ve just introduced the concepts of compiling and packaging modules. For more information, DZone has a number of good articles on modularity. A first stop would be their introduction to modules. Jenkov.com also has a very detailed tutorial.

I hope you found this series on modularity useful. Please share your comments and any questions you have.

Leave a Comment

Your email address will not be published. Required fields are marked *

Code like a Java Guru!

Thank You

We're Excited!

Thank you for completing the form. We're excited that you have chosen to contact us about training. We will process the information as soon as we can, and we will do our best to contact you within 1 working day. (Please note that our offices are closed over weekends and public holidays.)

Don't Worry

Our privacy policy ensures your data is safe: Incus Data does not sell or otherwise distribute email addresses. We will not divulge your personal information to anyone unless specifically authorised by you.

If you need any further information, please contact us on tel: (27) 12-666-2020 or email info@incusdata.com

How can we help you?

Let us contact you about your training requirements. Just fill in a few details, and we’ll get right back to you.

Your Java tip is on its way!

Check that incusdata.com is an approved sender, so that your Java tips don’t land up in the spam folder.

Our privacy policy means your data is safe. You can unsubscribe from these tips at any time.