The opens directive in Java 9 - java

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...).

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.

A package opened by a module, may be qualified or unqualified.
The opens directive in a module declaration declares a package to be
open to allow all types in the package, and all their members, not
just public types and their public members to be reflected on by APIs
that support private access or a way to bypass or suppress default
Java language access control checks.
--Documentation

Related

NoClassDefFoundError when adding classes to the classpath at runtime when I used abstract or interface in Main class

I know Java loads Classes in first Access (creating new Instance, calling static method or static field), but in this simple example I try to execute a jar file that uses some classes which there aren't in my ClassPath at run time. I expect (because of loading classes in first access) print my messages in static block and main method before an exception occurred. but I got "Exception in thread "main" java.lang.NoClassDefFoundError: com/example/DateAbstract" and nothing printed.
This occurred when I used an abstract class or interface in main class which that classes or interfaces are in another jar file.
public class Driver {
static { System.out.println("I am first.[static block]"); }
public static void main(String[] args) {
System.out.println("I am first.[ main method]");
DateAbstract date = new CustomDate();
System.out.println(date.sayDate());
}
in my another jar :
public class CustomDate extends DateAbstract {
#Override
public String sayDate() {
return new Date().toString();
}
public abstract class DateAbstract {
public abstract String sayDate();
}
when I use this code for add my classes to classpath at runtime. nothing changed. I got execption before execute static block.
public class Driver {
static {
System.out.println("I am first.[static block]");
try {
URL url = new File("lib/DateApi.jar").toURI().toURL();
URLClassLoader urlClassLoader = (URLClassLoader) URLClassLoader.getSystemClassLoader();
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
method.invoke(urlClassLoader,url);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
System.out.println("I am first.[ main method]");
DateAbstract date = new CustomDate();
System.out.println(date.sayDate());
}
}
Questions :
why is this happening and how to solve it ?
It’s not correct to say that in Java classes are loaded on their first access. You are confusing this with the initialization of a class, which implies executing the Java code of static initializer blocks and field initializers. The loading and verification might happen at an earlier time; the specification provides some freedom to the JVMs in this regard.
The key point here is that your main method instantiates an object of type CustomDate, stores it into a variable of the compile-time type DateAbstract and then tries to invoke sayDate() on that variable. This combination of instantiating CustomDate and invoking DateAbstract.sayDate() on it requires the verification of its correctness, i.e. whether CustomDate is a subtype DateAbstract. So the loading of these two classes will already happen at verification time.
You can easily check that this is the cause. If you change the type of the local variable date to CustomDate, the instantiated type and the receiver type of the method invocation are the same, so the correctness can be proven without loading the type, so it will be indeed deferred to the actual attempt to instantiate CustomDate, hence the messages will be printed.
Still, the loading time is an implementation-specific detail. A different JVM could load the referenced classes eagerly, even if they are not required for verification. The only safe way to ensure a deferred loading, is to use dynamic loading, e.g. Class.forName(String). Note that within the class detached this way, all types might be again referenced ordinarily. So if you do the dynamic loading once after the class path has been adjusted, there is not much impact on how you have to write the code nor its performance. Of course, having the code adjusting the class path and the code depending on it within the same class won’t work reliably.

Gradle release build - preserving method parameter names

We are creating an Android library with an inner interface class. The problem we are facing is that the method parameter names are not preserved for interface class in the release build aar file. Although .aar file works fine, this creates problem in editor when using autocompletion, Implement methods etc. Please note that proguard is disabled.
public class Test {
public interface TestInterface {
void testCallback(int ordernumber, int vendorid);
}
public boolean init(Context context);
}
In the debug build, class is preserved fine. However, in the release build, parameter names of interface methods are not preserved. Interestingly it preserves parameter names of class methods. This I verified using decompiler.
public class Test {
public interface TestInterface {
void testCallback(int paramInt1, int paramInt2);
}
public boolean init(Context context);
}
I also tried setting debuggable flag in buildconfig without any help.
Will appreciate any help.
The official oracle docs state that interfaces do not preserve parameter names, so the only solution is including the docs with the library: Preserving parameter/argument names in compiled java classes

Why does compiling a class containing static nested classes create a new .class file named "EnclosingClass$1"? [duplicate]

This question already has answers here:
Why is an anonymous inner class containing nothing generated from this code?
(5 answers)
Closed 7 years ago.
In the below code :
class EnclosingClass
{
public static class BiNode extends Sub.IBiLink { }
private static class Sub
{
private static class IBiLink
{
}
}
}
On compiling along with other .class files, I also see a file named "EnclosingClass$1.class" .Why has this been automatically created? Whats going on?
First have a look at the class access and propery modifier table from the JVM specifications.
Notice the ACC_SYNTHETIC flag which interpretation specify that it is not present in the source code (in simplier words, it will be added when the class is generated by the compiler).
Let's have a look at the bytecode of EnclosingClass$1.class (note that I will paste only the part that matter).
javap -v EnclosingClass$1.class
produce the following result
Classfile /C:/Users/jfrancoiss/Desktop/Nouveau dossier/EnclosingClass$1.class
Last modified 2015-03-31; size 190 bytes
MD5 checksum 5875440f1e7f5ea9a519d02fbec6dc8f
Compiled from "EnclosingClass.java"
class EnclosingClass$1
minor version: 0
major version: 52
flags: ACC_SUPER, ACC_SYNTHETIC
Notice that the access flags of the class contains ACC_SYNTHETIC.
The ACC_SYNTHETIC flag indicates that this class or interface was
generated by a compiler and does not appear in source code.
An other option to make sure the generated class is synthetic is to compile as
javac -XD-printflat EnclosingClass.java
which would produce
/*synthetic*/ class EnclosingClass$1 {
}
Great, but why generate a synthetic class ?
The Java reflection tutorial can help us understand this. Have a look at the comments in the SyntheticConstructor class
public class SyntheticConstructor {
private SyntheticConstructor() {}
class Inner {
// Compiler will generate a synthetic constructor since
// SyntheticConstructor() is private.
Inner() { new SyntheticConstructor(); }
}
}
So according on the comment, the synthetic class EnclosingClass$1.class was created because IBiLink was private.
Once again, the java reflection tutorial specify at this point
Since the inner class's constructor references the private constructor
of the enclosing class, the compiler must generate a package-private
constructor.
In our case, we do not see explicitely any constructor call, but we have this line
public static class BiNode extends Sub.IBiLink { }
Let's try compiling this code and see what happen
class EnclosingClass
{
//public static class BiNode extends Sub.IBiLink { }
private static class Sub
{
private static class IBiLink
{
}
}
}
No EnclosingClass$1.class generated.
More details noticed when debugging
Change
private static class IBiLink
to
protected static class IBiLink
notice that when compiling, EnclosingClass$1.class is not created.
why does protecting the class did not generate a synthetic class ?
Simply because when protecting the class, you implicitely get access to each of the super classes.
Why don't eclipse compiler generate a synthetic class ?
Eclipse use it built-in compiler, which you can configure it severity level.
By default, Access to a non-accessible member of an enclosing type is set to ignore as you can see on this image.
Change it for example to warning and you will get the following message.
which let me believe that eclipse, altought does not create an other class, will emulate it to simulate the synthetic member.

Default access specifier in Java is accessible from outside the class

class HelloWorld {
public static void main(String arg[]) {
System.out.println("Hello World!");
}
}
Using javac HelloWorld.java and java HelloWorld, the code compiles and runs well. Since default access specifier in Java is package, how is it possible? It must have protection from outsider...
Access modifier restricts access during compile time. But it is allowed to load a class with any access modifier, use reflection to find the main method and run it. This is what java tool does when lanching from a class. See http://docs.oracle.com/javase/6/docs/technotes/tools/windows/java.html
Default Access modifier means you can only access that class in that package.
what you are doing here is, running and compiling the class.
This has nothing to do with modifiers and accessibility.
You will always Run & Compile classes like that.
What matters is that your class is accessible in the class or package that is being run.
You can not access a class with Default modifier in sub package or other package. A default class will only be accessible i the same package, otherwise you will get compile time error.
As far as your code is concerned you are doing nothing like that.
Suppose -
class HelloWorld {
public static void main(String arg[]) {
System.out.println("Hello World!");
}
}
And
Class Hello extends HelloWorld{
// some code here
}
Now if you compile class Hello, then it will give you following error.
class, interface, or enum expected

java decompilation

When decompiling a specific jar using java decompiler (http://java.decompiler.free.fr/) I got some strange code I cannot identify what is. can someone help me? the code is something like:
Foo.access$004(Foo.this);
or this
Bar.access$006(Bar.this);
or else
Baz.access$102(Baz.this, true)
What are these methods access$004, access$006 and access$102?
Synthetic methods like this get created to support acessing private methods of inner classes. Since inner classes were not part of the initial jvm version, the access modifiers could not really handle this case. The solution was to create additional package-visible methods that delegate to the private implementation.
public class Example {
private static class Inner {
private void innerMethod() { ... }
}
public void test() {
Inner inner = ...
inner.innerMethod():
}
}
The compile would create a new method of the Inner class like this:
static void access$000(Inner inner) {
inner.innerMethod();
}
And replace the call in the test method like this:
Inner.access$000(inner);
The static access$000 is package visible and so accessible from the outer class, and being inside the same Inner class it can delegate to the private innerMethod.
These are auto-generated methods which are created by the compiler in some cases (for example when accessing private fields of another class directly, e.g., in case of nested classes).
See also What is the meaning of "static synthetic"? and Synthetic Class in Java.
If you get the relevant .class file (run jar through unzip), and run the .class file through JAD
JAD MyClass.class
then you may find that the output JAD file has decompiled that particular line in a more meaningful way, e.g.
Baz.access$102(Baz.this, true)
shows up in the JAD output as simply
myMemberVaiable = true
where myMemberVaiable is a member of class Baz that you will recognise.

Categories