Summary
I'm unable to reflectively instantiate a class across module boundaries. The class has package-level access, and I'm trying to instantiate it from not just outside the package, but from outside the module itself. According to my understanding, I'm allowed to do this, so long as the containing package has been open
ed by the containing module, and the instantiating module requires
the containing module. All I get for my attempted instantiation is an IllegalAccessException
Details
My app is configured as a "Modular Java project" in my Netbeans 11, and is configured to run on the Java 12 platform.
In the app, I have two modules:
mod.world
mod.vehicles
mod.world
is my "main" module -- it has the main()
method, and it declares that it requires
the other module mod.vehicles
mod.vehicles
defines a "protected" class (a class with package-level access) called vehicles.cars.Sedan
, in package vehicles.cars
mod.vehicles
declares that it opens vehicles.cars
In the main()
method, I attempt to instantiate the Sedan
class, using:
var myConstructor = Class.forName("vehicles.cars.Sedan").
getDeclaredConstructor();
myConstructor.newInstance();
What I Expect to See
I expect that the code successfully instantiates the Sedan
class, and the println()
inside the Sedan
constructor gets executed.
What I Actually Get
But this invocation of newInstance()
throws an IllegalAccessException
:
Exception in thread "main" java.lang.IllegalAccessException: class world.MyMainClass (in module mod.world) cannot access a member of class vehicles.cars.Sedan (in module mod.vehicles) with modifiers "public"
My Questions
According to the Java Language Specification (section 7.7.2 Exported and Opened Packages):
The opens directive specifies the name of a package to be opened by the current module. For code in other modules, this grants access at run time, but not compile time, to the public and protected types in the package, and the public and protected members of those types. It also grants reflective access to all types in the package, and all their members, for code in other modules.
-
My understanding of the above extract from the JLS is that I should be able to access the "protected" type
Sedan
, and its members, which includes the constructor. But why am I not able to use that constructor to instantiate theSedan
class reflectively? -
Which part of the Java Language Specification am I violating by attempting this instantiation?
-
Is my understanding of the term reflective access wrong? Is this term defined formally somewhere by Java? Couldn't find a formal definition of reflective access anywhere in the JLS for Java 12.
Here's the complete code:
module-info.java
for the mod.world
module:
module mod.world {
exports world;
requires mod.vehicles;
}
MyMainClass.java
, in package world
of module mod.world
:
package world;
import java.lang.reflect.InvocationTargetException;
public class MyMainClass {
public static void main (String[] args) throws ClassNotFoundException,
NoSuchMethodException,
InstantiationException,
IllegalAccessException,
InvocationTargetException {
// This statement succeeds.
var myConstructor = Class.forName("vehicles.cars.Sedan").
getDeclaredConstructor();
// This statement throws IllegalAccessException
myConstructor.newInstance();
}
}
module-info.java
for the mod.vehicles
module":
module mod.vehicles {
opens vehicles.cars;
}
Sedan.java
in package vehicles.cars
:
package vehicles.cars;
class Sedan {
public Sedan () {
System.out.println ("Inside constructor Sedan()");
}
}
Other Observation
The instantiation goes through successfully if I change the Sedan
class to a public
one.
Aucun commentaire:
Enregistrer un commentaire