FULL PRODUCT VERSION :
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7601]
A DESCRIPTION OF THE PROBLEM :
I encountered an AssertionError when compiling a work project with Java 1.8. It seems to be a bug when processing type annotations in some particular cases.
As far as I can tell, it happens only if I try to instantiate (1) an anonymous class (2) based on a generic superclass (3) with a generic constructor argument (4) that has a type annotation on one of its generic arguments (5) using an in-line constructor call expression for the constructor argument.
See the source files below for a minimal test case. My original code uses Eclipse���s nullness annotations package, I just copied one of them in the test case to make reproduction easier.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Place the two source files below in two appropriately named files/folders. Try compiling the Test class to check that it works. Then uncomment the line starting with ���//~��� and compile it again.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The code should compile.
ACTUAL -
With the last expression uncommented, the compiler throws an AssertionError.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
D:\debug>javac test\Test.java
An exception has occurred in the compiler (1.8.0_60). Please file a bug at the Java Bug Database (http://bugreport.java.com/bugreport/) after checking the database for duplicates. Include your program and the following diagnostic in your report. Thank you.
java.lang.AssertionError: annotation tree hasn't been attributed yet: @NonNull()
at com.sun.tools.javac.util.Assert.error(Assert.java:133)
at com.sun.tools.javac.util.Assert.checkNonNull(Assert.java:118)
at com.sun.tools.javac.comp.Check.validateTypeAnnotation(Check.java:2745)
at com.sun.tools.javac.comp.Attr$TypeAnnotationsValidator.visitAnnotation(Attr.java:4461)
at com.sun.tools.javac.tree.JCTree$JCAnnotation.accept(JCTree.java:2317)
at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:57)
at com.sun.tools.javac.tree.TreeScanner.visitAnnotatedType(TreeScanner.java:324)
at com.sun.tools.javac.comp.Attr$TypeAnnotationsValidator.visitAnnotatedType(Attr.java:4466)
at com.sun.tools.javac.tree.JCTree$JCAnnotatedType.accept(JCTree.java:2373)
at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:57)
at com.sun.tools.javac.tree.TreeScanner.visitTypeApply(TreeScanner.java:287)
at com.sun.tools.javac.tree.JCTree$JCTypeApply.accept(JCTree.java:2135)
at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
at com.sun.tools.javac.tree.TreeScanner.visitNewClass(TreeScanner.java:206)
at com.sun.tools.javac.comp.Attr$TypeAnnotationsValidator.visitNewClass(Attr.java:4529)
at com.sun.tools.javac.tree.JCTree$JCNewClass.accept(JCTree.java:1516)
at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:57)
at com.sun.tools.javac.tree.TreeScanner.visitNewClass(TreeScanner.java:207)
at com.sun.tools.javac.comp.Attr$TypeAnnotationsValidator.visitNewClass(Attr.java:4529)
at com.sun.tools.javac.tree.JCTree$JCNewClass.accept(JCTree.java:1516)
at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
at com.sun.tools.javac.tree.TreeScanner.visitExec(TreeScanner.java:175)
at com.sun.tools.javac.tree.JCTree$JCExpressionStatement.accept(JCTree.java:1296)
at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:57)
at com.sun.tools.javac.comp.Attr$TypeAnnotationsValidator.visitBlock(Attr.java:4557)
at com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:909)
at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
at com.sun.tools.javac.comp.Attr$TypeAnnotationsValidator.visitClassDef(Attr.java:4552)
at com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:693)
at com.sun.tools.javac.comp.Attr.validateTypeAnnotations(Attr.java:4450)
at com.sun.tools.javac.comp.Attr.attribClassBody(Attr.java:4374)
at com.sun.tools.javac.comp.Attr.attribClass(Attr.java:4249)
at com.sun.tools.javac.comp.Attr.attribClass(Attr.java:4178)
at com.sun.tools.javac.comp.Attr.attrib(Attr.java:4153)
at com.sun.tools.javac.main.JavaCompiler.attribute(JavaCompiler.java:1248)
at com.sun.tools.javac.main.JavaCompiler.compile2(JavaCompiler.java:901)
at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:860)
at com.sun.tools.javac.main.Main.compile(Main.java:523)
at com.sun.tools.javac.main.Main.compile(Main.java:381)
at com.sun.tools.javac.main.Main.compile(Main.java:370)
at com.sun.tools.javac.main.Main.compile(Main.java:361)
at com.sun.tools.javac.Main.compile(Main.java:56)
at com.sun.tools.javac.Main.main(Main.java:42)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
// file test/Test.java:
// -----------------------------------------
package test;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicReference;
import test.NonNull;
public class Test
{
{
// This works:
new AtomicReference<ArrayList<@NonNull Long>>(new ArrayList<@NonNull Long>());
// This also works:
ArrayList<@NonNull Long> list = new ArrayList<@NonNull Long>();
new AtomicReference<ArrayList<@NonNull Long>>(list) {};
// This crashes if uncommented:
//~ new AtomicReference<ArrayList<@NonNull Long>>(new ArrayList<@NonNull Long>()) {};
}
}
// file test/NonNull.java
// -----------------------------------------
package test;
import static java.lang.annotation.ElementType.TYPE_USE;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Documented
@Retention(RetentionPolicy.CLASS)
@Target({ TYPE_USE })
public @interface NonNull {
// marker annotation with no members
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
As can be seen from the test case, using a temporary variable ("list" in my case) for the argument avoids the problem. Not sure if this can be triggered in other conditions.
The issue is that it���s pretty hard to figure out where the problem is, because the assertion does not say what line in the source code triggers it.
In my case I used ���javac -verbose��� to find the problem file, and then I used binary search to find which line caused the problem.