JDK-8287968 : Compilation failure: java.lang.Thread.Builder is a preview API and is disabled by default
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 19
  • Priority: P3
  • Status: Closed
  • Resolution: Not an Issue
  • OS: generic
  • CPU: generic
  • Submitted: 2022-06-08
  • Updated: 2022-06-24
  • Resolved: 2022-06-24
Description
Referencing arbitrary `Builder` class inside Thread::run() causes compilation to fail with `java.lang.Thread.Builder is a preview API and is disabled by default` error.

OpenJDK version:

```
openjdk version "19-ea" 2022-09-20
OpenJDK Runtime Environment (build 19-ea+25-1892)
OpenJDK 64-Bit Server VM (build 19-ea+25-1892, mixed mode, sharing)
```

Reproducer sample class:
```
package com.example;

public class Builder {
    public static void main(String[] args) {
        new Thread() {
            public void run() {
                final Builder builder = new com.example.Builder();
                builder.buildNow();
            }
        }.start();
    }
    
    public void buildNow() {
    }
}
```


Compiler error (using "$JAVA_HOME/bin/javac" com/example/Builder.java):
```
src\main\java\com\example\Builder.java:7: error: Builder is a preview API and is disabled by default.
                final Builder builder = new com.example.Builder();
                      ^
  (use --enable-preview to enable preview APIs)
src\main\java\com\example\Builder.java:7: error: incompatible types: com.example.Builder cannot be converted to java.lang.Thread.Builder
                final Builder builder = new com.example.Builder();
                                        ^
src\main\java\com\example\Builder.java:8: error: cannot find symbol
                builder.buildNow();
                       ^
  symbol:   method buildNow()
  location: variable builder of type Builder
3 errors
```

The issue has been manifested in Apache CXF builds which we run regularly for every JDK early releases, it is a bit difficult to precisely pinpoint the build but it has been noticed first time in the OpenJDK 19-ea+22 and confirmed in 19-ea+25.

[1] https://ci-builds.apache.org/job/CXF/job/CXF-JDK19/189/console
Comments
Thanks Alan, please go ahead with closing this one
23-06-2022

The JEP, CSR, and RN have been updated to document the source compatibility issue with the nested interface that may arise with existing code that extends Thread. I don't think there is anything more we can do here so I plan to close this JBS issue.
23-06-2022

Thanks Alan, yes I made the change to fix the builds.
10-06-2022

We are working on text for JEP 425 to document the source compatibility issue. The CSR and RN will need to be updated too. Note that the JEP didn't add any top-level classes to java.lang. The conflict in this bug report is with nested interfaces, and specifically with java.lang.Thread.Builder and javax.ws.rs.sse.OutboundSseEvent.Builder when compiling code that extends Thread and uses the simple name Builder. I checked the apache/cxf repo and it looks like Andriy has already changed the two test cases where this arose to workaround the issue: - final Builder builder = sse.newEventBuilder(); + final OutboundSseEvent.Builder builder = sse.newEventBuilder();
10-06-2022

I note that this kind of issue is explicitly called out in the JEP: Adding classes and interfaces to the java.lang package is significant because a Java source file imports all the classes and interfaces in java.lang automatically, via an implicit import java.lang.*;. The meaning of import java.lang.*; does not depend on whether preview features are enabled or disabled. Even if preview features are disabled, a Record class being previewed in java.lang is imported by every source file, and may interfere with pre-existing imports of a Record class or interface from another package. --- I still think the onus is on the API developers to avoid using names that are highly likely to clash.
10-06-2022

Thanks for looking, Alan and David. > For this specific bug report, the submitter can workaround the issue by changing the declaration to use "var" or the fully qualified name of the example (com.example.Builder). That is correct but I would have expected to do that if `java.lang.Thread.Builder` would have been imported explicitly, but it is not (for obvious reasons). The compilation error (in this context) is very confusing because the presence of this new interface `java.lang.Thread.Builder` is essentially invisible to a developer. > The new APIs have been in loom EA builds since late 2019 and I don't think we've had any other reports to date. That is correct, at least for Apache CXF we do not run CI builds against loom/panama/... builds (as per JDK quality outreach program, we test against JDK stable and EA builds). The example provided is intentionally simplified, but there is really compatibility issue since Builder classes are all over the place, for example JAX-RS SSE scenario fails to compile now: ``` @GET @Path("sse") @Produces(MediaType.SERVER_SENT_EVENTS) public void forBook(@Context SseEventSink sink) { new Thread() { public void run() { final Builder builder = sse.newEventBuilder(); sink.send(createEvent(builder.name("book"), id + 1)); sink.close(); } } }.start(); } ``` > The alternative to rename Thread.Builder to something that would less likely to conflict is not appealing and has a lot of implications. I know that a lot of thoughts have been put into API, may be (as an option) moving `Thread.Builder` under `ThreadBuilders` could be considered? It is not a critical issue by all means, unexpected I would say in the context.
09-06-2022

Okay, I get your point. I think the only thing we can do is document the source compatibility issue. It's unfortunate but I wouldn't expect the scenario to be too common. The new APIs have been in loom EA builds since late 2019 and I don't think we've had any other reports to date. The source compatibility issue is also easy to workaround in a way that will continue to compile with older JDK releases if necessary. The alternative to rename Thread.Builder to something that would less likely to conflict is not appealing and has a lot of implications.
08-06-2022

Sorry, I don't think that Preview API are expected to be hidden - they exist, they just produce an error (or a warning, as appropriate) when used. Please see "Preview APIs in java.lang" in https://openjdk.java.net/jeps/12.
08-06-2022

Preview APIs are supposed to be "hidden" at compile time when not compiling with preview features enabled. So on the surface it is surprising that there is a compilation error but there may be more to this, and how it interacts with shadowing, that needs someone on javac to comment on. Given that it's a source compatibility issue then we'll need to document it in a release note. For this specific bug report, the submitter can workaround the issue by changing the declaration to use "var" or the fully qualified name of the example (com.example.Builder).
08-06-2022

This is an interesting aspect of preview features ... how should/can name clashes get resolved?
08-06-2022

This is a javac issue not a hotspot->compiler issue.
08-06-2022