JDK-8250769 : javac support for Preview APIs
  • Type: CSR
  • Component: tools
  • Sub-Component: javac
  • Priority: P3
  • Status: Closed
  • Resolution: Approved
  • Fix Versions: 17
  • Submitted: 2020-07-29
  • Updated: 2020-12-15
  • Resolved: 2020-12-08
Related Reports
CSR :  
Relates :  
Relates :  
Relates :  
Description
Summary
--------

JEP 12 "Preview Features" has been updated to define _Preview APIs_, and to clarify the use of classes which are declared using preview language features. The JDK's Java compiler, javac, needs to be updated to match these updates to JEP 12, and to adhere more precisely to JEP 12 overall.


Problem
--------

javac needs to be updated to match the updated requirements of JEP 12.


Solution
--------

Change javac as follows:

1. Preview APIs are split into two broad groups: normal and reflective. Normal preview APIs are subdivided by JEP 12 into three kinds -- essential, convenient, standalone -- for expository purposes; however, javac is interested only in the fact that code uses a normal preview API versus a reflective preview API, and not in which kind of normal preview API. The critical point is that normal preview APIs can only be used with the --enable-preview flag, while reflective preview APIs may be used without the --enable-preview flag.

2. Adhere to a long-standing JEP 12 requirement to provide a suppressible warning when code uses a class declared using a preview language feature. (Example. Consider the declaration `record Point(...) {}` which uses a preview language feature and must therefore be compiled with --enable-preview. The result is `Point.class`, a class file that can only be used with --enable-preview. Accordingly, to compile code that uses Point, such as `Point p = new Point(...)`, it has always been necessary to run javac with --enable-preview. However, JEP 12 further intended that any use of a preview language feature should generate a warning: direct use (`record ...`) generates an non-suppressible warning, and indirect use (`Point p = new Point(...)`) generates a suppressible warning. The latter was unfortunately not generated in JDK 15.)

3. Mark class files as depending on preview features (minor_version 65535) only if they need it. In JDK 15, all class files produced by javac when --enable-preview flag was provided were marked as depending on preview features -- even if the code in a class made no use of preview features. In JDK 16, only classes that use preview features will have their class files marked.


Specification
--------

Where use of a preview feature is detected (or use of a class declared using a preview language feature), javac behaves as shown in the table below. "Suppression" means that `@SuppressWarnings("preview")` is applied in the source code at the point where the preview feature (or a class declared using a preview language feature) is used/invoked/overridden.

<br/>
<table>
<tr>
<td>Use of ...</td>
<td><pre>--enable-preview</pre> <pre>No Suppression</pre></td>
<td><pre>--enable-preview</pre> <pre>Suppression</pre></td>
<td><pre>No --enable-preview</pre> <pre>No Suppression</pre></td>
<td><pre>No --enable-preview</pre> <pre>Suppression</pre></td>
</tr>

<tr>
<td>Preview language feature</td>
<td>mandatory warning</td>
<td>mandatory warning</td>
<td><strong>error</strong></td>
<td><strong>error</strong></td>
</tr>

<tr>
<td>A class declared using a preview language feature</td>
<td>mandatory warning</td>
<td>no warning</td>
<td><strong>error</strong></td>
<td><strong>error</strong></td>
</tr>

<tr>
<td>Normal preview API</td>
<td>mandatory warning [1]</td>
<td>no warning</td>
<td><strong>error</strong> [1]</td>
<td><strong>error</strong> [1]</td>
</tr>

<tr>
<td>Reflective preview API</td>
    <td>mandatory warning</td>
<td>no warning</td>
<td>mandatory warning</td>
<td>no warning</td>
</tr>

</table>

[1] Referring to a normal preview API _in the same module_ is allowed without a warning / error (--enable-preview / no --enable-preview, respectively) See "Special rules for declarations of preview APIs" in JEP 12.

The table above describes behavior that has existed in JEP 12 since inception, and subsumes a more limited table that described behavior for "APIs associated with preview language features" in an earlier CSR (JDK-8231411). The formulation of the table above is as follows:

- The rows "Preview language feature" and "A class declared using a preview language feature" describe longstanding behavior from JEP 12, prior to it dealing with APIs in any way.
- The row "Normal preview API" corresponds to the "Essential" row in the earlier CSR.
- The row "Reflective preview API" corresponds to the "Non-essential" row in the earlier CSR.

The precise output of javac for a "mandatory warning" is unchanged from JDK 15:

- With -Xlint:preview, a warning on each occurrence.
- With -Xlint:-preview, a summary at the end of the compilation, stating preview features have been used.

The default setting for the `preview` lint is unchanged from JDK 15:

- -Xlint:preview when no --enable-preview is present.
- -Xlint:-preview when --enable-preview is present.

An explicit -Xlint setting overrides this default.

javac marks a class file as depending on preview features (minor_version 65535) under the following conditions:

- The corresponding source code uses a preview language feature, or a class declared using a preview language feature, or a normal preview API. (Use of a reflective preview API is exempt; see "Special rule for use of reflective preview APIs" in JEP 12.)
- The corresponding source code is part of a preview API. (See "Special rules for declarations of preview APIs" in JEP 12.)
- javac uses a preview VM feature in the generated class file.

This is a change from JDK 15, where all class files are marked as depending on preview features when compiling with --enable-preview.
 
Comments
Re-approving for JDK 17 rather than 16.
15-12-2020

Moved to Approved with amended version of JEP 12.
08-12-2020

Thanks for noticing that the "Example Use of Preview Features" section described old javac behavior. (That behavior wasn't really desirable in the early days of preview features, but it was what we had, so JEP 12 described it.) Now that javac in JDK 16 is more precise about which class files are marked as depending on preview features, I have updated the item quoted above, as follows: > - If no compile-time error occurs, then a class file emitted by javac _depends on the preview features of Java SE $N_ if the source code corresponding to the class file refers to (i) a preview language feature of Java SE $N, or (ii) a class or interface declared using a preview language feature of Java SE $N, or (iii) a normal preview API of Java SE $N. (Source code references to reflective preview APIs are exempted, as described in "Special rules for use of reflective preview APIs" above.) In addition, I made editorial updates to align the section more strongly with the "Use of Preview Features" section, and I recorded in an earlier section that a reflective preview API may live in `java.*` or `javax.*` *or* `com.sun.source.tree.*` (to account for the Compiler Tree API). These updates do not affect the CSR per se, but I mention them because they are visible in the attachment `jep12-2020-12-07.md` which serves as the latest archival copy of JEP 12.
07-12-2020

The attached JEP text states in its Example Use of Preview Features section: > When the preview features of Java SE $N are enabled (--release $N > --enable-preview): > ... > Every class file emitted by javac depends on the preview features of Java SE $N, regardless of whether the source > code corresponding to the class file actually uses preview language > features or preview APIs of Java SE $N. This appears to contradict the stated change in behavior from JDK 15: > This is a change from JDK 15, where all class files are marked as > depending on preview features when compiling with --enable-preview. Please clarify.
06-12-2020

We have attached snapshots of JEP 12 and of the proposed text for JLS 1.5 ("Preview Features"). The Compatibility Risk Description has also been filled out to deal with the marking of class files and the suppressible warning for indirect use of preview language features.
02-12-2020

Moving to Provisional, not Approved. This CSR could be summarized as "implement the current semantics of JEP 12." As such, since JEP 12 can in principle changed at any time (and has already been changed over the years the JEP has evolved), please attach or otherwise include some kind of stand-alone and readable representation of corresponding state of the JEP to this CSR. This is to facilitate the CSR's archival function. If there are JLS updates to support this change, they should be included in the CSR as well. Please highlight the behavioral changes in the Compatibility Risk Description; if I've interpreted the specification correctly, the minor class file version is set to 65535 in fewer cases than before.
02-12-2020

I have clarified the formulation of the table. The preview feature semantics are intricate because they handle a wide variety of constructs -- language features, code declared using language features, and APIs playing one of numerous roles. (For the purpose of this CSR, I set aside VM features and class files created to use them.) The motivation for, say, handling normal APIs differently than reflective APIs is documented in JEP 12. On the matter of non-suppressible warnings from javac that cause a `-Werror` compilation to fail: the presence of a warning (hence, error) implies javac detected use of a preview language feature, which implies that `--enable-preview` was given. (If `--enable-preview` had not been given, then javac would have stopped compilation with an error for the use of a preview language feature.) When someone enables preview features, what do we want them to know about the code they're compiling? JEP 12 says: "In our judgment, it is important to remind developers about the use of preview language features and preview APIs in source code, even when preview features are enabled at compile time -- the developer compiling the code might not be the developer who wrote it. We believe that a suppressible warning is sufficient to flag the use of a preview API (or a type declared using a preview language feature), since API names passed to new or used in method calls are easy to spot even if the warning is suppressed. *In contrast, we believe a suppressible warning is not sufficient to flag the use of a preview language feature, since language constructs can be subtle and might be overlooked if the warning is suppressed.* Since warnings mandated by the JLS are suppressible with @SuppressWarnings("..."), they are not strong enough to flag the use of a preview language feature. Warnings specific to javac can be arbitrarily strong, hence the use of a javac lint warning in the third case above." That is, we are loathe to let anyone use preview language features "silently". If there is a concern specific to code in the JDK, please state it plainly.
26-08-2020

Moving to Provisional. As a comment on the revised JEP 12 semantics, they are a bit intricate. Before this CSR is Finalized for the second phase of review, please explicitly indicate which row/column of the table in the Specification section indicate changed behavior. Reiterating a comment made from previous version of the preview feature proposal, I think it needs to be a requirement that code using preview features can be compiled successfully with javac under "-Werror -Xlint:all". In other words, some of the "warnings" may be messages of concern from javac but not formal warnings.
24-08-2020