Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8030049

RoundEnvironment.getElementsAnnotatedWith receives wrong elements

XMLWordPrintable

    • b02
    • Verified

        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.

              jlahoda Jan Lahoda
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              6 Start watching this issue

                Created:
                Updated:
                Resolved: