Overview
We have discussed Java 9 Modularity and Module System. Also we have discussed How to create first Module in Java 9 using eclipse. Here we will discuss in detail of Module Descriptor and different directives.
As we mentioned, a module must provide a module descriptor—metadata that specifies the module’s dependencies, the packages the module makes available to other modules, and more. A module descriptor is the compiled version of a module declaration that’s defined in a file named
0 1 2 3 |
module modulename { } |
The module declaration’s body can be empty or may contain various module directives, including
Let’s understand one by one with examples.
1. requires
A requires module directive specifies that this module depends on another module—this relationship is called a module dependency. Each module must explicitly state its dependencies. When module A requires module B, module A is said to read module B and module B is read by module A. To specify a dependency on another module, use requires, as in:
Example
Let’s take an example, We have two modules: A and B. Module A is used to display a message using a class called

Project A Module Descriptor :
0 1 2 3 4 |
module A { exports com.codenuclear.a; } |
Project B Module Descriptor :
0 1 2 3 4 |
module B { requires A; } |
Here, we are specifying that module B requires the services of A,
DisplayMessage.java
0 1 2 3 4 5 6 7 8 9 10 |
package com.codenuclear.a; public class DisplayMessage { public void displayMessage(String message) { System.out.println(message); } } |
PostMessage.java
0 1 2 3 4 5 6 7 8 9 10 11 12 13 |
package com.codenuclear.b; import com.codenuclear.a.DisplayMessage; public class PostMessage { public static void main(String s[]) { DisplayMessage displayMsgService=new DisplayMessage(); displayMsgService.displayMessage("Hello World !!"); } } |
Output
There is also a
2. requires transitive
To specify a dependency on another module and to ensure that other modules reading your module also read that dependency—known as
Example
Let’s continue with our example, with Module A and B, Let’s have a third module C which is depends on Module B. So dependencies are like
We have modified PostMessage class from Module B which returns the DisplayMessage object by calling getDisplayMessage() method, Which shows Module B is dependent on A and any other module depends on Module B also needs access of Module A.
Here making a dependency of module B in C will not include dependency of module A, For that, we need to change module descriptor for module A in module B from

Project A Module Descriptor :
0 1 2 3 4 |
module A { exports com.codenuclear.a; } |
Project B Module Descriptor :
0 1 2 3 4 5 |
module B { requires transitive A; exports com.codenuclear.b; } |
Project C Module Descriptor :
0 1 2 3 4 |
module C { requires B; } |
PostMessage.java
0 1 2 3 4 5 6 7 8 9 10 11 |
package com.codenuclear.b; import com.codenuclear.a.DisplayMessage; public class PostMessage { public DisplayMessage getDisplayMessage() { return new DisplayMessage(); } } |
RetrieveDisplayMessage.java
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package com.codenuclear.c; import com.codenuclear.a.DisplayMessage; import com.codenuclear.b.PostMessage; public class RetrieveDisplayMessage { public static void main(String[] args) { PostMessage postMsgObj=new PostMessage(); DisplayMessage disMsg=postMsgObj.getDisplayMessage(); disMsg.displayMessage("Hello World !!"); } } |
Output
3. exports and exports…to
An exports module directive specifies one of the module’s packages whose public types (and their nested public and protected types) should be accessible to code in all other modules. An exports…to directive enables you to specify in a comma-separated list precisely which module’s or modules’ code can access the exported package—this is known as a qualified export.
As per example, To get access of module A in B, module descriptor of the module A having export of package
0 1 2 3 4 |
module A { exports com.codenuclear.a; } |
4. open, opens and opens…to
A key motivation of the module system is strong encapsulation. Before Java 9, reflection could be used to learn about all types in a package and all members of a type—even its private members—whether we wanted to allow this capability or not. Thus, nothing was truly encapsulated.
By default, a type in a module is not accessible to other modules unless it’s a public type and we export its package. We expose only the packages which we want to expose. With Java 9, this also applies to reflection.
4.1 Allowing Runtime-Only Access to a Package
An opens module directive of the form
indicates that a specific package’s public types (and their nested public and protected types) are accessible to code in other modules at runtime only. Also, all of the types in the specified package (and all of the types’ members) are accessible via reflection.
Example
In the above example, Lets say method
Project B Module Descriptor :
0 1 2 3 4 5 6 |
module B { requires transitive A; exports com.codenuclear.b; opens com.codenuclear.b; } |
0 1 2 3 4 |
module C { requires B; } |
PostMessage.java
0 1 2 3 4 5 6 7 8 9 10 11 |
package com.codenuclear.b; import com.codenuclear.a.DisplayMessage; public class PostMessage { private DisplayMessage getDisplayMessage() { return new DisplayMessage(); } } |
Have you noticed scope of the
RetrieveDisplayMessage.java
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
package com.codenuclear.c; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import com.codenuclear.a.DisplayMessage; import com.codenuclear.b.PostMessage; public class RetrieveDisplayMessage { public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { PostMessage postMsgObj=new PostMessage(); /** * Method is no more accessible directly as its scope is changed from public to private, * Hence calling it through reflection. */ Class cls = postMsgObj.getClass(); Method methodcall1 = cls.getDeclaredMethod("getDisplayMessage"); methodcall1.setAccessible(true); //Changing scope of method. DisplayMessage disMsg= (DisplayMessage) methodcall1.invoke(postMsgObj); disMsg.displayMessage("Hello World !!"); } } |
Output
4.2 Allowing Runtime-Only Access to a Package By Specific Modules
An
indicates that a specific package’s public types (and their nested public and protected types) types are accessible to code in the listed module(s) at runtime only. Also, all of the types in the specified package (and all of the types’ members) are accessible via reflection to code in the specified modules.
4.3 Allowing Runtime-Only Access to All Packages in a Module
If all the packages in a given module should be accessible at runtime and via reflection to all other modules, you may open the entire module, as in
0 1 2 3 4 |
open module modulename { // module directives } |
5. Restricted Keywords
The keywords
We mentioned that there is also a
That’s all for Module Descriptor and Directives in Java 9, Hope you liked it. Keep Learning and Sharing 🙂 !!