JDK-8030049 : RoundEnvironment.getElementsAnnotatedWith receives wrong elements
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 7u45
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2013-12-10
  • Updated: 2014-09-23
  • Resolved: 2014-01-10
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8 JDK 9
8u20Fixed 9 b02Fixed
Related Reports
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
On the Mac:

bash-3.2$ java -version
java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)
bash-3.2$ javac -version
javac 1.7.0_45

On the Linux
bash-3.2$ java -version
java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)
bash-3.2$ javac -version
javac 1.7.0_45


ADDITIONAL OS VERSION INFORMATION :
Linux desktop 2.6.18-164.el5 #1 SMP Tue Aug 18 15:51:48 EDT 2009 x86_64 x86_64 x86_64 GNU/Linux

Darwin laptop 12.5.0 Darwin Kernel Version 12.5.0: Sun Sep 29 13:33:47 PDT 2013; root:xnu-2050.48.12~1/RELEASE_X86_64 x86_64

A DESCRIPTION OF THE PROBLEM :
I declare an annotation processor as follows:

@SupportedAnnotationTypes({ "ExistingAnnotation"})
public class DemoAnnotationProcessor extends AbstractProcessor {
../..
}

In the process method [1] inside this processor, the resolution of the annotated elements is inconsistent. Here is the code being used:

Set<? extends Element> annotatedElements = roundEnv.getElementsAnnotatedWith(ExistingAnnotation.class);

When there are missing dependencies for the compilation, which would cause an "error: cannot find symbol" later, the set of annotatedElements improperly contains all such unresolved annotations, in addition to the properly annotated elements.

This is a change in behavior from JDK6. It causes confusing problems when the annotation processing step is used only for code generation (because there is no message explaining the lacking types if the annotation processing step throws an exception), and contradicts what getElementsAnnotatedWith() [2] is supposed to do.

[1] http://docs.oracle.com/javase/7/docs/api/javax/annotation/processing/Processor.html#process%28java.util.Set,%20javax.annotation.processing.RoundEnvironment%29
[2] http://docs.oracle.com/javase/7/docs/api/javax/annotation/processing/RoundEnvironment.html#getElementsAnnotatedWith%28javax.lang.model.element.TypeElement%29

REGRESSION.  Last worked in version 6u45

ADDITIONAL REGRESSION INFORMATION:
Where the failure does not repro:

java version "1.6.0_45"
Java(TM) SE Runtime Environment (build 1.6.0_45-b06)
Java HotSpot(TM) 64-Bit Server VM (build 20.45-b01, mixed mode)



STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Here are the three files for the repro. Instructions at the end

-----ExistingAnnotation.java ------
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExistingAnnotation {}
-----------------------------------


-------HelloWorld.java ------
@ExistingAnnotation
public class HelloWorld{
    
    @UnexistingAnnotation
    String someField;

    public static void main(String args[]){
System.out.println("Hello, world.");
    }
}
---------------------------


-------DemoAnnotationProcessor.java-------

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic.Kind;
import javax.tools.JavaFileObject;

@SupportedAnnotationTypes({ "ExistingAnnotation"})
public class DemoAnnotationProcessor extends AbstractProcessor {
    /**
     * Whether the mirror Element e is annotated with an annotation whose class is c
     * @param e
     * @param c
     * @return
     */
    private boolean isAnnotatedWith(Element element, Class<?> c){
    for(AnnotationMirror a: element.getAnnotationMirrors()){
    Elements elements = processingEnv.getElementUtils();
    TypeElement activitiesTypeElement = elements.getTypeElement(c.getCanonicalName());
    if(a.getAnnotationType().asElement().equals(activitiesTypeElement))
    return true;
    }
    return false;
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
    
        if (!roundEnv.processingOver()) {
            processingEnv.getMessager().printMessage(Kind.NOTE, "DemoAnnotationProcessor.process() invoked.");
    
    Set<? extends Element> annotatedElements = roundEnv.getElementsAnnotatedWith(ExistingAnnotation.class);
            for (Element annotatedElement : annotatedElements) {
            if( ! isAnnotatedWith(annotatedElement, ExistingAnnotation.class)){
            processingEnv.getMessager().printMessage(Kind.ERROR, "This element " + annotatedElement + " is not annotated with " + ExistingAnnotation.class);
            continue;
            }
    }


}
        else {
            processingEnv.getMessager().printMessage(Kind.NOTE, "Processing finished");
        }
    
return false;

    }
}
------------------------

# set path to use JDK 7
javac ExistingAnnotation.java
javac DemoAnnotationProcessor.java

bash-3.2$ javac -processorpath . -processor DemoAnnotationProcessor -proc:only HelloWorld.java
HelloWorld.java:4: error: cannot find symbol
    @UnexistingAnnotation
     ^
  symbol:   class UnexistingAnnotation
  location: class HelloWorld
warning: No SupportedSourceVersion annotation found on DemoAnnotationProcessor, returning RELEASE_6.
warning: Supported source version 'RELEASE_6' from annotation processor 'DemoAnnotationProcessor' less than -source '1.7'
Note: DemoAnnotationProcessor.process() invoked.
error: This element someField is not annotated with interface ExistingAnnotation
HelloWorld.java:4: error: cannot find symbol
    @UnexistingAnnotation
     ^
  symbol:   class UnexistingAnnotation
  location: class HelloWorld
Note: Processing finished
2 errors
2 warnings

Note the error reported by the annotation processor.



EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The expected result is that the annotation processor would not return an error, because calling getElementsAnnotatedWith on the environment would only return the proper elements.
ACTUAL -
Note the error reported in "steps to reproduce".

According to my testing, all the annotations that can not be resolved to a type are returned by getElementsAnnotatedWith.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
The code is included in "steps to reproduce" above.
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Make sure all the annotation types are defined.
Comments
ILW=HLM (I: does not work according to the specification=H; L: does not seem to be very common=L, W: workaround exists, but maybe difficult for the user to find out what is wrong and how to workaround=M)
10-03-2014

Suspect this change in behavior was introduced by JDK-6498938 back in JDK 7.
06-01-2014

Release team: Approved for deferral.
12-12-2013

The cause appears to be that Types.isSameType is used to detect the elements annotated with the given annotation, and that considers the error type to be the same as any other type.
12-12-2013