Summary
Produce an error/warning for method that override/implement a preview method.
Problem
Consider a method declared as a preview method in an interface I or a class C (using the unexported JDK-private annotation @PreviewFeature
). A good example comes from Project Loom, which declares the preview method ofVirtual
in class Thread
.
In Java 18, a concrete class D that implements I
or extends C
and implements I's method or overrides C's method does not receive an error or warning at compile time. The lack of error or warning is a problem, because D is clearly dependent on the preview API in I or C. An error or warning is due on the method in D which implements I's method or overrides C's method.
Note that the interface I or the class C is not itself a preview API. For example, the class Thread
is not a preview API even though it has a preview method ofVirtual
from Project Loom.
If D is an abstract class, then it can implements I
or extends C
without implementing I's method or overriding C's method. In this case, no error or warning is needed. The first concrete subclass E of the abstract class D is responsible for declaring a concrete method that implements or overrides the preview method in I or C. Accordingly, the concrete method in E that implements or overrides the preview method is the artifact which needs an error or warning.
Once a concrete class has implemented or overridden the preview method in I or C (and received an error or warning for doing so), then subclasses of that concrete class do not need any kind of error or warning relating to the preview method in I or C. The concrete class forms a barrier between the part of the class hierarchy that depends on the preview method, and the part of the class hierarchy that doesn't. Even if the concrete class has an abstract subclass F, and F re-abstracts the preview method, it is not necessary to give a warning or error for F's re-abstracted method.
Solution
javac will be fixed to produce errors/warnings for methods that directly implement or override a preview method.
Consider a (currently non-existing) instance preview method in Thread:
package java.lang;
public class Thread {
@PreviewFeature(feature=TEST)
public void demo() {}
}
Now, consider the following examples:
package java.util;
public class Test1 extends Thread {
@Override
public void demo() {} //no warning or error, as it is in the same module
}
package test; //in a user module "m"
public class Test2 extends Thread {
} //no warning or error, as the "demo" method is not overridden
package test;
public class Test3 extends Thread {
@Override
public void demo() {} //a preview error when compiling without --enable-preview, a preview warning when compiling with --enable-preview, subject to further @SuppressWarnings and/or -Xlint:+/-preview
}
package test;
public class Test4 extends Test3 {
@Override
public void demo() {} //no warning or error, as the appropriate diagnostics was already given in the super class
}
package test;
public class Test5 extends Test2 {
@Override
public void demo() {} //a preview error when compiling without --enable-preview, a preview warning when compiling with --enable-preview, subject to further @SuppressWarnings and/or -Xlint:+/-preview
}
If the preview method would be a reflective preview method:
package java.lang;
public class Thread {
@PreviewFeature(feature=TEST, reflective=true)
public void demo() {}
}
then the Test3 and Test5 cases would be altered:
package test;
public class Test3 extends Thread {
@Override
public void demo() {} //a preview warning when compiling with or without --enable-preview, subject to further @SuppressWarnings and/or -Xlint:+/-preview
}
package test;
public class Test5 extends Test2 {
@Override
public void demo() {} //a preview warning when compiling with or without --enable-preview, subject to further @SuppressWarnings and/or -Xlint:+/-preview
}
If the preview method was static (reflective or not):
package java.lang;
public class Thread {
@PreviewFeature(feature=TEST)
public static void demo() {}
}
there would be no preview-related errors or warnings for any subclasses. (Although there may be traditional "instance method cannot override static" errors.)
The existing behavior is described in depth here: https://bugs.openjdk.java.net/browse/JDK-8250769
The proposed change effectively fixes the javac implementation to interpret direct method overriding as "Use of" a preview method per JDK-8250769. The overriding and overridden methods may both be declared abstract, or any of them can be declared abstract, or both may be concrete. A method that does not directly override a preview method is not considered to be a "Use of" the preview method.
Specification
(Recall from JLS 1.5 that: "Some preview APIs are described as reflective by the Java SE Platform Specification, principally in the java.lang.reflect, java.lang.invoke, and javax.lang.model packages. ... All preview APIs not described as reflective in the Java SE Platform Specification are normal.)
A method that directly implements or overrides a preview method outside of the module that declares the method will get either:
- a non-suppressible compile-time error (for normal preview methods when preview mode is disabled), or
- a suppressible preview warning (for reflective preview methods when preview mode is disabled, or normal preview methods when preview mode is enabled).
- csr of
-
JDK-8282823 javac should constrain more uses of preview APIs
- Resolved
- relates to
-
JDK-8195734 JEP 12: Preview Features
- Completed