I'm reading the draft of the Java 9 specification but this phrase is not clear to me:
The opens directive specifies the name of a package to be opened by the current module. This makes public and protected types in the package, and their public and protected members, be accessible to code in other modules at run time only. It also makes all types in the package, and all their members, be accessible via the reflection libraries of the Java SE Platform.
If the opens makes public and protected accessible at runtime only, what does meaning that all types in the packages area accessible via reflection?
I don't understand the difference between runtime and reflection.
It seems like the opened package makes accessible only public and protected at runtime (via reflection?) and also other packages not specified with type and members accessible vie reflection (also private...).
The official Reference Implementation for Java SE 9 (JSR 379) is based solely upon open-source code available from the JDK 9 Project in the OpenJDK Community.
In order to provide reflective access to your module, Java 9 introduced the open keyword. You can create an open module by using the open keyword in the module declaration. An open module grants reflective access to all of its packages to other modules.
What is Java 9 Module? A Module is a self-describing collection of Code, Data, and some Resources. It is a set of related Packages, Types (classes, abstract classes, interfaces etc) with Code & Data and Resources.
Let's say you write some code that uses a public class from a library.
import somelibrary.somepackage.SomeClass; // <-- public class from a library.
public class Main {
public static void main(String[] args) {
SomeClass.doSomething();
}
}
You then compile this code, and it compiles fine, since the class you're using is public
.
Now, in the next version of the library, the package is added to a module, but not exported. That means that if you try to run your code with this new module on the runtime module path, it would throw an exception because you're trying to access an encapsulated package.
In order to make your code work again, you could use the command line option to open this module to your code, so that it can continue to use the encapsulated package.
Alternatively, the creator of the library could add opens somepackage;
to the module definition of the library. That would allow you to run your code using this new version, but not compile with it. I.e. the public
and protected
members are only accessible at runtime, but there is no reflection involved.
The same goes for when you extend a class, and want to access a protected
member of a super class that is in the encapsulated package.
But the opens directive does not change the fact that, if in the next version of a library, a method or field is made private
, that you get an IllegalAccessError
if you try to use it:
class SomeClass { // <-- the class in the library
public static void doSomething() {
System.out.println("doSomething"); // contrived example code
}
}
...
public class Main {
public static void main(String... args) throws Exception {
SomeClass.doSomething(); // this call compiles fine,
}
}
Then, in the next version of the library doSomething
is made private
:
private static void doSomething() {...}
And re-compiled. But if you try to run the old version of Main
with the new version of SomeClass
you get an IllegalAccessError
.
In short, opens only works for members that are still public
or protected
in the new version of the library.
However, in the case of reflection, you can always access a private
member, by using setAccessible(true)
:
public static void main(String... args) throws Exception {
Method m = SomeClass.class.getDeclaredMethod("doSomething");
m.setAccessible(true);
m.invoke(null); // works Fine
}
So in the case of reflection, opens would also make encapsulated private members accessible again.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With