Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8283380

javac should constrain more uses of preview APIs

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Approved
    • Icon: P4 P4
    • 19
    • tools
    • None
    • source
    • minimal
    • Hide
      Given that `@PreviewFeature` is a JDK-private annotation, user code cannot declare preview methods. The OpenJDK 18 code does not declare any normal preview methods, so the change i this CSR should not lead to new errors reported for user code. However, the OpenJDK 18 code does declare several reflective preview methods, and new warnings may be produced for these.
      Show
      Given that `@PreviewFeature` is a JDK-private annotation, user code cannot declare preview methods. The OpenJDK 18 code does not declare any normal preview methods, so the change i this CSR should not lead to new errors reported for user code. However, the OpenJDK 18 code does declare several reflective preview methods, and new warnings may be produced for these.
    • Other
    • Implementation

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

            jlahoda Jan Lahoda
            abuckley Alex Buckley
            Alex Buckley
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: