Java 9 Module Example

By Arvind Rai, 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 Module Example

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.

How to Create a Module

A module is created using module 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;
} 
Now suppose we have one more module named as 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 as com.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
|   |    |   | 
Find the code.
module-info.java
module com.cp { 
} 
In 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!";
   }
} 
Main.java
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());
   }
} 
We will compile the code using command prompt. Go to the 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 
1. mods/com.cp is the location to keep compiled Java files. com.cp is the module name. By convention we keep source files inside src directory and compiled modules inside mods directory.
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
|   |    |   | 
src is the root directory for source files and mods is the root directory for compiled files.
Now run the code using command prompt.
java --module-path mods -m com.cp/com.cp1.Main 
Output
Hello World! 
In the above Java command
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.
Java 9 Module Example

Example 2: Module Dependency

Here we will create two modules, one module will be dependent on another module. We are creating modules com.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 
|   |    |   | 
Find the 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;
} 
AddressUtil.java
package com.add;
public class AddressUtil {
   public String getCity(int id) {
	   return id + "- Noida" ;
   }
} 
Now find the code for 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;
} 
EmpMain.java
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));
   }
} 
The 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 
2. To compile 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 
3. After compilation, class files will be stored in mods directory. Find the project structure for src and mods directories after compilation.
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 
|   |    |   | 
Now run the program using following command.
java --module-path mods -m com.employee/com.emp.EmpMain 
Output
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 modules com.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 . 
Suppose we want to create our JARs within a directory such as 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 . 
Now create JAR for 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 . 
In this way we have two JARs within 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 
We can use -p option in place of --module-path as following.
java -p mlib -m com.employee 
Output
100- Noida 
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 
For linux, we need to replace ';' with ':' in command line.
$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 
2.
--module-source-path
Specifies the module source path.
$ javac -d mods --module-source-path src $(find src -name "*.java") 
3.
--describe-module
Describe the module.
java --describe-module java.base 
Describe module contained in JAR.
jar --describe-module --file=mlib/com.employee.jar 
4.
--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 
5.
--list-modules
List down all modules in Java
java --list-modules 
6.
--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 { 
} 
com.cp2/module-info.java
module com.cp2 { 
  requires com.cp1;
} 
In this case the classes of packages of the 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;
} 
com.cp2/module-info.java
module com.cp2 { 
} 
In this case, again the classes of packages of the 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;
} 
com.cp2/module-info.java
module com.cp2 { 
  requires com.cp1;
} 
In this case the classes of packages of the 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 Guide
Modular Development with JDK 9
Understanding Java 9 Modules

Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI
LEARN MORE








©2024 concretepage.com | Privacy Policy | Contact Us