Java 9 Module Example
December 15, 2018
This page will walk through Java 9 Module Example. A Module is a set of packages designed for reuse. In Java 9, Java programs are Modules. Java Module is the main feature introduced in Java 9 release. In Java we have classes, packages and now modules, too. Before Java 9 module, Java programs are packages.
As we know that in Java, a package can access only public methods of another packages. In a large code base, where there is large number of packages, any package can access public method of any package which was not a better accessibility control. Now using Module, we can control the accessibility between packages for public methods of the classes.
A Package is the set of classes and a Module is the set of packages. Public methods of packages are only available for packages within the module. We can export the packages from its module to make it available to packages of other modules. So only exported packages from a module will be available to packages of other modules. We can also export packages to only friend modules and not for all.
A module is created with
module-info.java
file name and module
keyword is used to specify module name. Base module is java.base
which is automatically resolved by all modules. java.base
module contains the packages such as java.lang
, java.io
, java.net
, java.util
etc. All the packages exported by java.base
module are automatically available to all the modules.
Find the diagram that shows relation between module, packages and classes.
Java 9 Platform Module System (JPMS) is a very important software engineering technology. Java 9 modularity is the result of Project Jigsaw and this will help developers to build and maintain large system in simpler way.
Here we will discuss how to create, compile and run modules in our Java project.
Contents
How to Create a Module
A module is created usingmodule
in module-info.java
file. module
gives a name to module. Other keywords that are used for module definition are requires
, exports
, uses
, opens
, provides
.
Now we will create a module named as
com.address
that has com.add
package. Find the module definition code.
com.address/module-info.java
module com.address { exports com.add; requires java.base; }
exports
exports a package and requires
specify a module name required by this module. Here we have exported com.add
package to make it available to other modules.
java.base
is the base module which is required by all and it is automatically resolved by all modules. So we need not to write it in our code. We can write above code as following, too.
com.address/module-info.java
module com.address { exports com.add; }
com.employee
that requires com.address
module. Find the code for com.employee
module.
com.employee/module-info.java
module com.employee { requires com.address; }
Example 1: Simple Module
Here we will create a module with some packages and compile it and run it using command prompt. In our example, we will create a module named ascom.cp
and two packages with some classes. By convention we need to keep the source code for the module in the directory that is the name of the module. Find the project structure of our demo project.
java-9-demo | |--src | | | |--com.cp | | | | | |--module-info.java | | | | | |--com | | | | | | | |--cp1 | | | | | | | | | |--Main.java | | | | | | | |--cp2 | | | | | | | | | |--MsgUtil.java | | | |
module-info.java
module com.cp { }
module-info.java
, we need not to use requires
for java.base
module. It will be resolved automatically.
Now find other Java files.
MsgUtil.java
package com.cp2; public class MsgUtil { public String getMsg() { return "Hello World!"; } }
package com.cp1; import com.cp2.MsgUtil; public class Main { public static void main(String[] args) { MsgUtil ob = new MsgUtil(); System.out.println(ob.getMsg()); } }
java-9-demo
directory using command prompt and run following command.
javac -d mods/com.cp src/com.cp/module-info.java src/com.cp/com/cp2/MsgUtil.java src/com.cp/com/cp1/Main.java
2. Then we specify files to be compiled in the command arguments.
After compilation we have following project structure with
.java
and .class
files.
java-9-demo | |--src | | | |--com.cp | | | | | |--module-info.java | | | | | |--com | | | | | | | |--cp1 | | | | | | | | | |--Main.java | | | | | | | |--cp2 | | | | | | | | | |--MsgUtil.java | | | | | | | | |--mods | | | |--com.cp | | | | | |--module-info.class | | | | | |--com | | | | | | | |--cp1 | | | | | | | | | |--Main.class | | | | | | | |--cp2 | | | | | | | | | |--MsgUtil.class | | | |
Now run the code using command prompt.
java --module-path mods -m com.cp/com.cp1.Main
Hello World!
1. The option --module-path specifies module path. Its value can be one or more directories that contain modules.
2. The -m option specifies the main module and the value after slash is the class name of the main class in the module.
Find the print screen of the output using command prompt.
Example 2: Module Dependency
Here we will create two modules, one module will be dependent on another module. We are creating modulescom.address
and com.employee
in our example. Find the project structure.
java-9-demo | |--src | | | |--com.address | | | | | |--module-info.java | | | | | |--com | | | | | | | |--add | | | | | | | | | |--AddressUtil.java | | | |--com.employee | | | | | |--module-info.java | | | | | |--com | | | | | | | |--emp | | | | | | | | | |--EmpMain.java | | | |
com.address
module code. In com.address
we are exporting com.add
package. So all the public methods of the classes of this package will be accessible to other modules which requires com.address
module.
com.address/module-info.java
module com.address { exports com.add; }
package com.add; public class AddressUtil { public String getCity(int id) { return id + "- Noida" ; } }
com.employee
module. This module requires com.address
module. Hence all the public methods of the classes of exported packages in com.address
module will be available to com.employee
module.
com.employee/module-info.java
module com.employee { requires com.address; }
package com.emp; import com.add.AddressUtil; public class EmpMain { public static void main(String[] args) { AddressUtil ob = new AddressUtil(); System.out.println(ob.getCity(100)); } }
EmpMain
class is using AddressUtil
public method. It became possible because the module com.address
has exported com.add
package and com.employee
module has used requires
for com.address
module.
Now we will compile the code. Go to the
java-9-demo
directory using command prompt and run following command. Here we will compile modules separately.
1. Compile the module
com.address
javac -d mods/com.address src/com.address/module-info.java src/com.address/com/add/AddressUtil.java
com.employee
module, we also need to provide module path for module location to resolve dependent module. Find the command to compile com.employee
module.
javac --module-path mods -d mods/com.employee src/com.employee/module-info.java src/com.employee/com/emp/EmpMain.java
java-9-demo | |--src | | | |--com.address | | | | | |--module-info.java | | | | | |--com | | | | | | | |--add | | | | | | | | | |--AddressUtil.java | | | |--com.employee | | | | | |--module-info.java | | | | | |--com | | | | | | | |--emp | | | | | | | | | |--EmpMain.java | | | | | | |--mods | | | |--com.address | | | | | |--module-info.class | | | | | |--com | | | | | | | |--add | | | | | | | | | |--AddressUtil.class | | | |--com.employee | | | | | |--module-info.class | | | | | |--com | | | | | | | |--emp | | | | | | | | | |--EmpMain.class | | | |
java --module-path mods -m com.employee/com.emp.EmpMain
100- Noida
Compile multi-modules using one command
We can compile our all modules in one go using following linux command.
$ javac -d mods --module-source-path src $(find src -name "*.java")
module-source-path
specifies the Java file source root directory.
Create JAR
Here we will discuss how to create a JAR with module. In the above example we have two modulescom.address
and com.employee
within mods
directory. We will create a JAR com.address.jar
for com.address
module and JAR com.employee.jar
for com.employee
module. Go to the java-9-demo
directory using command prompt. Find the Java command to create JAR for com.address
module.
jar --create --file=com.address.jar --module-version=1.0 -C mods/com.address .
mlib
directory. Then first create mlib
directory parallel to src
directory and then run the following command.
jar --create --file=mlib/com.address.jar --module-version=1.0 -C mods/com.address .
com.employee
specifying main class.
jar --create --file=mlib/com.employee.jar --main-class=com.emp.EmpMain --module-version=1.0 -C mods/com.employee .
mlib
directory i.e. com.address.jar
and com.employee.jar
.
As we have specified main class in the
com.employee.jar
, so to execute the module, we need not to specify main class.
java --module-path mlib -m com.employee
-p
option in place of --module-path
as following.
java -p mlib -m com.employee
100- Noida
jlink
jlink
is the linker tool that links a set of modules with their transitive dependencies. jlink
is used to create a custom modular run-time image (JEP 220). We can restructure the JDK and JRE run-time images to accommodate our modules and to improve performance, security and maintainability. jlink
works for the modules packaged in JAR or JMOD format.
We will use
jlink
with our previous example. In our demo within java-9-demo
directory, we have mlib
directory containing com.address.jar
and com.employee.jar
files. Go to the java-9-demo
directory using command prompt and run the jlink
command as following.
jlink --module-path $JAVA_HOME/jmods;mlib --add-modules com.employee --output employeeapp
$JAVA_HOME/jmods contains
java.base.jmod
and the other standard and JDK modules.
Now look into the
employeeapp
directory, the jlink
command has populated a custom modular run-time image.
Java Command Line Options for Modules
Here we will provide some Java command line options for modules.1.
--module-path
Specifies the module path. We need to provide one or more directories that will contain modules.
java --module-path mods -m com.cp/com.cp1.Main
--module-source-path
Specifies the module source path.
$ javac -d mods --module-source-path src $(find src -name "*.java")
--describe-module
Describe the module.
java --describe-module java.base
jar --describe-module --file=mlib/com.employee.jar
--add-modules
Adds the specified modules to the default set of modules.
jlink --module-path $JAVA_HOME/jmods;mlib --add-modules com.employee --output employeeapp
--list-modules
List down all modules in Java
java --list-modules
--patch-module
Adds or overrides classes in a module. It is used in place of
-Xbootclasspath/p
.
Accessibility
In JDK 9 we have following accessibility.1. public to everyone.
2. public but only to friend modules.
3. public only within a module.
4. protected
5. package
6. private
Here we will discuss public to everyone scope. Suppose we have a module
com.cp1
with package com.cp.entity
and one more module com.cp2
.
Case-1:
com.cp2
module requires com.cp1
module but com.cp1
module does not export com.cp.entity
package.
com.cp1/module-info.java
module com.cp1 { }
module com.cp2 { requires com.cp1; }
com.cp2
module will not be able to access any public method of classes of com.cp.entity
package of com.cp1
module because the module com.cp1
has not exported com.cp.entity
package.
Case-2:
com.cp2
module has not used requires
for com.cp1
.
com.cp1/module-info.java
module com.cp1 { exports com.cp.util; }
module com.cp2 { }
com.cp2
module will not be able to access any public method of classes of com.cp.entity
package of com.cp1
module because com.cp2
module has not used requires
for com.cp1
.
Case-3: Now find the following case.
com.cp1/module-info.java
module com.cp1 { exports com.cp.util; }
module com.cp2 { requires com.cp1; }
com.cp2
module will be able to access any public method of classes of com.cp.entity
package of com.cp1
module.
References
Project Jigsaw: Module System Quick-Start GuideModular Development with JDK 9
Understanding Java 9 Modules