使用匿名参数化类类型推断的javac NPE时,JDK 11.0.2编译失败

Mik*_*kov 12 java type-inference javac compiler-bug java-11

代码(spring-web 5.1.2)

public static void main(String[] args) {
    RestTemplate restTemplate = new RestTemplate();

    HttpHeaders headers = new HttpHeaders();
    headers.set(HttpHeaders.AUTHORIZATION, "token");
    HttpEntity<Object> requestEntity = new HttpEntity<>(headers);

    ResponseEntity<Object> test = restTemplate.exchange(
            "https://example.com",
            HttpMethod.GET,
            new HttpEntity<>(headers),
            new ParameterizedTypeReference<>() { // fails here
            });
}
Run Code Online (Sandbox Code Playgroud)

OracleJDK 1.8(预期输出)

无法推断org.springframework.core.ParameterizedTypeReference的类型参数

原因:不能对匿名内部类使用“ <>”

OracleJDK 11.0.2(非预期输出)

编译器消息文件损坏:key = compiler.misc.msg.bug arguments = 11.0.2,{1},{2},{3},{4},{5},{6},{7} java.lang jdk.compiler / com.sun.tools.javac.comp.Flow $ FlowAnalyzer.visitApply(Flow.java:1235)处的.NullPointerException,jdk.compiler / com.sun.tools.javac.tree.JCTree $ JCMethodInvocation.accept( JcTree.java:1634),位于jdk.compiler / com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49),位于jdk.compiler / com.sun.tools.javac.comp.Flow $ BaseAnalyzer。在jdk.compiler / com.sun.tools.javac.comp.Flow $ FlowAnalyzer.visitVarDef(Flow.java:989)处扫描(Flow.java:398)
...

如果我将菱形运算符更改为显式类型

new ParameterizedTypeReference<>(){}new ParameterizedTypeReference<Object>(){}

然后代码可以在两个JDK上成功编译。

它是已知的编译器错误吗?

Mik*_*kov 16

错误(JDK-8212586)已提交,并已在版本12中修复

最小的可验证示例:

public static void main(String[] args) {
    new Bug<>(){};
}

static class Bug<T> {

    Bug() {
        test(new ParameterizedTypeReference<>(){});
    }

    void test(ParameterizedTypeReference<T> typeReference) {
    }
}
Run Code Online (Sandbox Code Playgroud)

一些细节。


该修复程序也已反向移植到JDK 11- https://bugs.openjdk.java.net/browse/JDK-8220578

从JDK 11.0.4开始可用。

  • java 11.0.6 有同样的问题 (3认同)
  • @MirceaStanciu [修复已向后移植](https://bugs.openjdk.java.net/browse/JDK-8220578) 并将在 JDK 11.0.4 中提供。更新了答案。 (2认同)

小智 10

正如之前的评论所指出的,问题出在参数化匿名类上,例如,当使用 Guava 中的 TypeToken 时,这不起作用

public List<SomeClass> list() {
    return getData(new TypeToken<>() { });
}
Run Code Online (Sandbox Code Playgroud)

但这确实有效:

public List<SomeClass> list() {
    return getData(new TypeToken<List<SomeClass>>() { });
}
Run Code Online (Sandbox Code Playgroud)

我在 11.0.3 - 11.0.7 版本中尝试过,所有版本都包含该错误。


小智 8

我有同样的错误,你需要创建一个函数:

ParameterizedTypeReference<Object> createParameterizedTypeReference(){ return new ParameterizedTypeReference<>(){}; }
Run Code Online (Sandbox Code Playgroud)

并称之为:

ResponseEntity<Object> test = restTemplate.exchange(
"https://example.com",
HttpMethod.GET,
new HttpEntity<>(headers),
createParameterizedTypeReference() { 
});
Run Code Online (Sandbox Code Playgroud)


小智 5

Java 11.0.7也有同样的问题。

这改变自:

new ParameterizedTypeReference<>() {
})
Run Code Online (Sandbox Code Playgroud)

对此:

new ParameterizedTypeReference<HashMap<String, MyClass>>() {
})
Run Code Online (Sandbox Code Playgroud)