In the preceding sections, you saw that the module system enforces encapsulation. A module can only access explicitly exported packages from another module. In the past, it was always possible to overcome pesky access
restrictions by using reflection. As you have seen in Chapter 5 of Volume I, reflection can access private members of any class.
However, in the modular world, that is no longer true. If a class is inside a module, reflective access to non-public members will fail. Specifically, recall how we accessed private fields:
Field f = obj.getClass().getDeclaredField(“salary”);
double value = f.getDouble(obj);
f.setDouble(obj, value * 1.1);
The call f.setAccessible(true) succeeds unless a security manager disallows private field access. However, it is not common to run Java applications with security managers, and there are many libraries that use reflective access. Typical examples are object-relational mappers, such as JPA, that automatically persist objects in databases and libraries that convert between objects and XML or JSON, such as JAXB and JSON-B.
If you use such a library, and you also want to use modules, you have to be careful. To demonstrate this issue, let us place the ObjectAnalyzer class from Chapter 5 of Volume I into a module com.horstmann.util. That class has a toString method that prints the fields of an object, using reflection.
A separate v2ch09.openpkg module contains a simple Country class:
public class Country
private String name;
private double area;
public Country(String name, double area)
this.name = name;
this.area = area;
// . . .
A short program demonstrates how to analyze a Country object:
public class Demo
public static void main(String args) throws ReflectiveOperationException
var belgium = new Country(“Belgium”, 30510);
var analyzer = new ObjectAnalyzer();
Now compile both modules and the Demo program:
javac com.horstmann.util/module-info.java \
javac -p com.horstmann.util v2ch09.openpkg/module-info.java \
java -p v2ch09.openpkg:com.horstmann.util -m v2ch09.openpkg/com.horstmann.places.Demo
The program will fail with an exception:
Exception in thread “main” java.lang.reflect.InaccessibleObjectException:
Unable to make field private java.lang.String com.horstmann.places.Country.name
accessible: module v2ch09.openpkg does not “opens com.horstmann.places” to module
Of course, in pristine theory, it is wrong to violate encapsulation and poke around in the private members of an object. But mechanisms such as object- relational mapping or XML/JSON binding are so common that the module system must accommodate them.
Using the opens keyword, a module can open a package, which enables reflective access to all instances of classes in the given package. Here is what our module has to do:
With this change, the ObjectAnalyzer will work correctly.
A module can be declared as open, such as
open module v2ch09.openpkg
An open module grants runtime access to all of its packages, as if all packages had been declared with exports and opens. However, only explicitly exported packages are accessible at compile time. Open modules combine the compiletime safety of the module system with the classic permissive runtime behavior.
Recall from Chapter 5 of Volume I that JAR files can contain, in addition to class files and a manifest, file resources which can be loaded with the method Class.getResourceAsStream, and now also with Module.getResourceAsStream. If a resource is stored in a directory that matches a package in a module, then the package must be opened to the caller. Resources in other directories, as well as the class files and manifest, can be read by anyone.
Source: Horstmann Cay S. (2019), Core Java. Volume II – Advanced Features, Pearson; 11th edition.