If one module reads another then, in some situations, it should logically also read some other modules.

The platform’s java.sql module, e.g., depends upon the java.logging and java.xml modules, not only because it contains implementation code that uses types in those modules but also because it defines types whose signatures refer to types in those modules. The java.sql.Driver interface, in particular, declares the public method

public Logger getParentLogger();

where Logger is a type declared in the exported java.util.logging package of the java.logging module.

Suppose, e.g., that code in the com.foo.app module invokes this method in order to acquire a logger and then log a message:

String url = ...;
Properties props = ...;
Driver d = DriverManager.getDriver(url);
Connection c = d.connect(url, props);
d.getParentLogger().info("Connection acquired");

 

If the com.foo.app module is declared as above then this will not work: The getParentLogger method returns a Logger, which is a type declared in the java.logging module, which is not readable by the com.foo.app module, and so the invocation of the info method in the Logger class will fail at both compile time and run time because that class, and thus that method, is inaccessible.

One solution to this problem is to hope that every author of every module that both depends upon the java.sql module and contains code that uses Logger objects returned by the getParentLogger method remembers also to declare a dependence upon the java.logging module. This approach is unreliable, of course, since it violates the principle of least surprise: If one module depends upon a second module then it is natural to expect that every type needed to use the first module, even if the type is defined in the second module, will immediately be accessible to a module that depends only upon the first module.

We therefore extend module declarations so that one module can grant readability to additional modules, upon which it depends, to any module that depends upon it. Such implied readability is expressed by including the transitive modifier in a requires clause. The declaration of the java.sql module actually reads:

module java.sql {
    requires public java.logging;
    requires public java.xml;
    exports java.sql;
    exports javax.sql;
    exports javax.transaction.xa;
}

 

The transitive  modifiers mean that any module that depends upon the java.sql module will read not only the java.sql module but also the java.logging and java.xml modules. The module graph for the com.foo.app module, shown above, thus contains two additional dark-blue edges, linked by green edges to the java.sql module since they are implied by that module:

Module Implied readability

Module Implied readability

The com.foo.app module can now include code that accesses all of the public types in the exported packages of the java.logging and java.xml modules, even though its declaration does not mention those modules.

In general, if one module exports a package containing a type whose signature refers to a package in a second module then the declaration of the first module should include a requires transitive dependence upon the second. This will ensure that other modules that depend upon the first module will automatically be able to read the second module and, hence, access all the types in that module’s exported packages.

Module javadeveloperzone.base

base-module

base-module

module-info.java

module javadeveloperzone.base{
   exports com.javadeveloperzone.model;
}

Demo.java

package com.javadeveloperzone;
import com.javadeveloperzone.Student;
public class Demo{
  public static void main(String ... args){
    System.out.println("Niceee... weldone... welcome to your first module program..");
    Student student= new  Student(1,"JavaDeveloperZone");
    System.out.println(student.getName());
  }
}

 Student.java

package com.javadeveloperzone.model;
public class Student{
  public int no;
  public String name;
  public Student(int no,String name){
    this.no=no;
    this.name=name;
  }
  public String getName(){
    return this.name;
  }
}

 StudentSecure.java

package com.javadeveloperzone.internal;
public class StudentSecure{
  public int no;
  public String name;
  public StudentSecure(int no,String name){
    this.no=no;
    this.name=name;
  }
  public String getName(){
    return this.name;
  }
 }

Module javadeveloperzone.foo

module-info.java

module javadeveloperzone.foo {
    requires transitive javadeveloperzone.base;
  exports com.javadeveloperzone.foo;
}

 FooDemo.java

package com.javadeveloperzone.foo;
import com.javadeveloperzone.model.Student;
public class FooDemo{
  public static void main(String ... args){
    System.out.println("Foo modules is accessing javadeveloperzone.base module");
    Student student = new  Student(1,"FooStudent");
    System.out.println(student.getName());
  }
  public static Student getStundetFactory(){
    return new Student(1,"FooStudent");
  }
}

Module javadeveloperzone.bar

module-info.java

module javadeveloperzone.bar{
 requires javadeveloperzone.foo;
}

BarDemo.java

package com.javadeveloperzone.bar;
import com.javadeveloperzone.model.Student;
public class BarDemo{
 public static void main(String ... args){
 Student student = com.javadeveloperzone.foo.FooDemo.getStundetFactory();
 System.out.println(student.getName());
 }
}

 

 

 

Was this post helpful?

Leave a Reply

Your email address will not be published. Required fields are marked *