I have already discussed many theoretical concepts about “Java 9 Module System” and also developed couple of examples using CMD prompt and IDEs in my previous posts.Now I’m going to discuss about “How to Develop and Test Implied Readability Between Modules With IntelliJ IDEA IDE” in this post.
In this series of “Java 9 Module System” posts, it is my fifth post. Before reading this post, please go through my previous post by clicking the following links to understand some basics about Java 9 Modules.
Post Brief Table of Content:
- What is Readability?
- What is Accessibility?
- What is Implied Readability?
- Develop Module Dependency With Bad Approach
- Test Module Dependency For Bad Approach
- Develop Implied Readability(Good Approach)
- Advantages of Implied Readability
What is Readability?
If Module-1 directly depends on Module-2, then it is know as “Module-1 Reads Module-2”. In other words, we can say that “Module-2 is Readable by Module-1”.
So, It is know as Readability relationship between Module-1 and Module-2. Let us explore it with some JDK 9 Modules using below diagram.
Here “java.sql” module reads “java.xml”, “java.base” and “java.logging” modules.
What is Accessibility?
If Module-1 has Readability Relationship with Module-2, then Module-1 can “Access” all Public API of Module-2. It is know as Accessibility Relationship between those two modules. As we discussed in my previous posts, a Module can have only Public API or both Public and Private API.
In simple words, Public API means Public Types. If you don’t understand it well, We will discuss on “How to develop Public and Private API” in my coming posts.
Both Readability and Accessibility concepts are the basis for achieving the two main Goals of Java 9 Module System:
- Reliable Configuration
- Strong Encapsulation
We can define Readability and Accessibility Relationships between modules using the following concepts:
- exports clause
- requires clause
- public modifier
- to clause
We will discuss all these concepts in this post with examples except last one (check for my coming posts).
What is Implied Readability?
If Module-1 reads on Module-2 and Module-2 reads on Module-3, then Module-1 reads Module-3. This kinds of Transitive Dependency is known as “Implied Readability” from Moudle-3 to Module-1.
It is also known as Implied Dependency.
Suppose if we have relationship between three modules as shown in the below diagram.
“LastName” Module depends on “FirstName”, “FullName” Module depends on Both Modules : “FirstName” and “LastName”. That means there is a Transitive Dependency between these three modules:
“FullName ==> LastName ==> FirstName”
In Java 9 Module System, We have two approaches to resolve these Module Dependencies.
1. Bad Approach
This approach solves Transitive Dependency between modules without using “Implied Readability”.
Here “FullName” imports both modules using “requires” clauses as shown below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
module FirstName{ exorts FirstName; } module LastName{ requires FirstName; exports LastName; } module FullName{ requires FirstName; requires LastName; exports FullName; } |
It is bad approach because LastName is already importing FirstName Module then why don’t we get that import feature to FullName Module?? Instead of using that, FullName is importing both modules. It works perfectly, however it’s not a recommended approach.
In real-time projects, we will have this kind of dependencies on many modules, is it good to import all modules?? Definitely NO, right.
2. Good Approach
This approach solves Transitive Dependency between modules using “Implied Readability” Technique.
Here “FullName” imports only LastName module using “requires” clause, but it gets “FirstName” automatically without importing it as shown below:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
module FirstName{ exorts FirstName; } module LastName{ requires public FirstName; exports LastName; } module FullName{ requires LastName; exports FullName; } |
This good approach is also know as “Implied Readability” in Java 9 Module System. So we can implement “Implied Readability” using “public” modifier as shown in the above example.
We will develop both approaches in the coming sections to understand it well.
Please go through this post Java 9 HelloWorld Module with Eclipse and IntelliJ IDEs to know on “How to develop Java 9 Modules using IntelliJ IDE”.
Develop Bad Approach
In this section we will develop bad approach to solve this Transitive Dependency without using “Implied Readability”. Once we are comfortable with this approach, we will develop right approach in the coming sections.
Let us understand this approach with this digarm:
-
- Create an IntelliJ IDEA Project
Project Name: ImpliedDependency
-
- Develop FirstName Module Code
- Create FirstName Module
- Develop FirstName Module Code
Module Name: : com.firstname
-
-
- Create FirstName Module Package
-
Package name: com.firstname.name
-
-
- Create Java Component(s)
-
FirstName.java
1 2 3 4 5 6 7 8 9 |
package com.firstname.name; public class FirstName { public String getFirstName() { // Some logic to get FirstName return "FName"; } } |
- Create FirstName Module Descriptor
module-info.java
1 2 3 4 5 |
module com.firstname { exports com.firstname.name; } |
-
- Develop LastName Module Code
- Create LastName Module
Module Name: : com.lastname
-
- Create LastName Module Package
Package name: com.lastname.name
-
- Create Java Component(s)
LastName.java
1 2 3 4 5 6 7 8 9 |
package com.lastname.name; public class LastName { public String getLastName() { // Some logic to get LastName return "LName"; } } |
Name.java
1 2 3 4 5 6 7 8 9 10 11 |
package com.lastname.name; import com.firstname.name.FirstName; public class Name { public String getName() { FirstName fname = new FirstName(); LastName lname = new LastName(); return fname.getFirstName() + " " + lname.getLastName(); } } |
- Create LastName Module Descriptor
module-info.java
1 2 3 4 5 6 |
module com.lastname { requires com.firstname; exports com.lastname.name; } |
As this module is dependent on FirstName Module, we should add “requires” clause to that module as shown in the above example.
-
- Develop FullName Module Code
- Create FullName Module
Module Name: : com.fullname
-
- Create FullName Module Package
Package name: com.fullname.name
-
- Create Java Component(s)
MiddleName.java
1 2 3 4 5 6 7 8 9 |
package com.fullname.name; public class MiddleName { public String getMiddleName() { // Some logic to get MiddleName return "MName"; } } |
FullName.java
1 2 3 4 5 6 7 8 9 10 11 12 13 |
package com.fullname.name; import com.firstname.name.FirstName; import com.lastname.name.LastName; public class FullName { public String getFullName() { FirstName fname = new FirstName(); MiddleName mname = new MiddleName(); LastName lname = new LastName(); return fname.getFirstName() + " " + mname.getMiddleName() + " " + lname.getLastName(); } } |
- Create FullName Module Descriptor
module-info.java
1 2 3 4 5 6 7 |
module com.fullname { requires com.firstname; requires com.lastname; exports com.fullname.name; } |
As this module is dependent on FirstName and LastName Modules, we should add requires clauses to both of them as shown in the above example.
Develop Test Module and Test Bad Approach
In this section, we will develop a Test Module to test this Bad Approach.
-
- Create Test Module
Module Name: : com.name.test
-
- Create Test Module Package
Package name: com.name.test
-
- Create Java Component(s)
NameTester.java
1 2 3 4 5 6 7 8 9 10 |
package com.name.test; import com.fullname.name.FullName; public class NameTester { public static void main(String a[]){ FullName fullName = new FullName(); System.out.println("Name = " + fullName.getFullName()); } } |
- Final Project looks like below.
- Run the NameTester class
Output:-
1 2 3 |
<span style="color: #008000;"><strong><code> Name = FName MName LName </code></strong></span> |
It works perfectly, however it is not a recommended approach. Let us develop same application using “Implied Readability” Technique.
Develop and Test Implied Dependency
-
- Please follow same steps as we did for Bad approach.
- Change “LastName” Module Descriptor
module-info.java
1 2 3 4 5 6 |
module com.lastname { requires public com.firstname; exports com.lastname.name; } |
Here we can observe that “public” modifier before Module name. When we use this in requires clause as shown in the above Module Descriptor, that means any Module which reads this “LastName” Module can also reads “FirstName” Module automatically. No need to use extra “requires” clause.
- Change “FullName” Module Descriptor
module-info.java
1 2 3 4 5 6 |
module com.fullname { requires com.lastname; exports com.fullname.name; } |
Here we are not using extra “requires” clause for “FirstName” Module. Still, it can reads that module because of “LastName” Module’s “Implied Readability” Technique.
- Use same Tester module to test this application.
Same output for this application too.
NOTE:-
Here we are using just few modules. However, it is not the same case in Real-time projects. A Real-time Module may depend on more Modules and it is not the right approach to import all of them. Am I right??
Few Important Points to Remember
In this section, we will briefly discuss about some important points to remember about Java 9 Module System.
- Every Module, by definition reads itself.
- Java 9 Module System does NOT supoort Cyclic Graphs that means it supports only Acyclic Graphs.
- Two or more Modules may have same package names. That means we can use same package names in two different Modules.
- By default, all Java 9 Modules (JDK Modules or User Define Modules) depends on “java.base” Module.
That’s it all about “Develop and Test Implied Dependency With Eclipse IDE” topic. We will discuss some more concepts about Java SE 9 Modules Development in my coming posts.
Please drop me a comment if you like my post or have any issues/suggestions/type errors.
Thank you for reading my tutorials.
Happy Java SE 9 Learning!