In this article, I will be talking about the Modules(Java Platform Module System) which where introduced as part of Java9, when Java9 was first introduced in September 21, 2017, it came out with lot many features already and Java Modules are said to be the best feature of Java so far. We will learn about Java Modules in detail and talk about why it is so important and what made it so popular among Java developers.
What is a Java Module?
A Java Module is essentially a collection of related packages and resources with a module descriptor file which contains information related to the Module. When we create a Java Module, we are not only organizing our code, but we are also determining what piece is publicly accessible outside the module. Let’s also talk about the module descriptor which happens to be a file containing vital information about the Module. When the module is created, a module descriptor is also included.
Following information is kept inside module descriptor.
- Name – That is the name of the module
- Dependencies – List of modules, this module depends on.
- Public Packages – The packages it explicitely makes available to other modules
- Services offered – The services it offers to other modules
- Services consumed – The services it will consume
- Reflection Permission – Allows other modules to use reflection to access the private members of a package.
A module will always have a module descriptor which specifies the metadata as mentioned above. A module descriptor is a compiled version of a module declaration that’s defined in a file named module-info.java.
Naming convention for modules – The naming convention for modules should be same as packages i.e we should not have numbers, hyphens to delimit the modules. However, dots can be used to delimit the modules if needed.
Note – By deault all packages in the module are module private.
What is the main goal of Java Platform Module System?
The main goal of this feature was to allow the user to create their own modules and control them to develop their applications. Modular programming has the been the main goal of Java Module System
Why do we need Java Modules?
- Use only relevant modules.
- Less coupling between components
- Modules will hide unwanted details and security can be achieved.
Strong Encapsulation – The packages in a module are accessible to other modules only if the module explicitely exports them.
Java modules will essentially provide resusability, security and modular programming.
We can also list the JDK’s modules with the following command.
java –list-modules
The above command lists the standard modules that implement the Java language SE Specification, JavaFX modules, JDK specific modules and Oracle specific modules. Each module name is followed by a version string –@9 indicates that the module belongs to Java9.
Also, the module declaration body can be left empty or it may have modules directives like requires, exports, provides…with, uses and opens, we can discuss these later in the artile but let’s see what happens when we compile the module, it will create the module descriptor, which is stored in a file named module-info.class in the module’s root folder.
Now, let’s talk about the module directive in brief, these directives are essentially the restricted keywords and used with module decalaration. Also, they can used be used as identifiers anywhere else in the code.
- requires – This directive mentions that, this module depends on another module and this relationship is called module dependency.
Usage – requires modulename; - exports and exports to – An exports module directive specifies one of the module’s packages whose public types should be accessible to code in all other modules.
- uses – A uses module directive specifies a service used by this module—making the module a service consumer.
- provides with – A provides…with module directive specifies that a module provides a service implementation—making the module a service provider.
- open, opens, and opens…to – Prior to Java 9, reflection could be used to access all types in a package and all members of a type—even its private members. Thus, nothing was truly encapsulated. However the Java module’s primary object was to provide strong encapsulation. By default, a type in a module is not accessible to other modules unless it’s a public type and you export its package. You expose only the packages you want to expose. With Java 9, this also applies to reflection.
Note – Java9’s Module System has a “java.base” module, it is also knows as the base module, it is said to be an independent module and does not depend on any other module. By default, all other module depends on the base module. It’s default module for all JDK Modules and User-Defined Modules.
Java Modules in Action
How to create a Java Module?
Following are the steps to create a module
Step1. Create a directory structure, eg – com.deepak
Step2. Module decalaration – Declare a module with the keyword module, followed by a unique module name and a module body like below
module modulename {
}
example – module com.deepak.hello {
}
Module declaration has to be done inside the module-info.java file under the package name of you choice.
Example – You have a package name com.deepak where you have a file named module-info.java and the module-info.java will have the above module declaration.
module-info.java
module com.deepak.hello {
}
Step3. Add the source code in the module
By convention, the source code of a module to lie in same directory, which happens to be the name of the module.
Step4. Compile Java Module – Now create a mod directory and compile the user-defined module to mods directory using the following command.
javac -d mods/com.deepak.hello {PATH_TO_MODULE_INFO_FILE} {PATH_TO_JAVA_FILE}
Step5. Run the module – Let’s run the module to see the output generated with the following command.
java –module-path mods/ –module com.deepak.hello/com.deepak.hello.Hello
So far so good, now what if I have 2 modules which are independent for now. However, I want to access one module in another. Remember we talked module directives, this is where module directives comes into picture, we will see this with the help of an example.
Let’s say we have two modules welcome and hello, now what I want to do is, I want to access hello module’s function in welcome module. So, I will make the following changes to the modules.
module com.deepak.hello {
exports com.deepak.hello;
}
module com.deepak.welcome {
requires com.deepak.hello;
}
Where the requires keyword indicates a dependency on hello module and exports indicates the packages which are to be made available to other modules which will be requiring it.
Here, welcome ——–> hello, welcome module depends on hello module.
Download Java 9 here
Modular applications have a lot many advantages over non-modular applications. Modularity is essentially an architectural principle that can prevent messy code.
That’s pretty much it from the article, full code can be found on the GitHub repository, feel free to fork it and start practicing the examples. If you have any feedback or queries, please do let me know in the comments. Also, if you liked the article, please give me a thumbs up and I will keep writing blogs like this for you in the future as well. Keep reading and Keep coding 🙂