fikr4n
fikr4n

Reputation: 3420

How to get field's type annotation in Java Annotation Processing?

For example, I have this code:

@Retention(RetentionPolicy.SOURCE)
public @interface ClassAnnotation {
}

@ClassAnnotation
public class AnnotatedClass {
}

@ClassAnnotation
public class AnotherAnnotatedClass {

    private AnnotatedClass someField;
    private int intIsNotAnnotated;
}

And this processor to preprocess it in compile time:

@SupportedAnnotationTypes({ "com.example.ClassAnnotation" })
@SupportedSourceVersion(SourceVersion.RELEASE_6)
public class AwesomeProcessor extends AbstractProcessor {

    public boolean process(Set<? extends TypeElement> annotations,
            RoundEnvironment roundEnv) {
        // Skipped for brevity...
        // For each annotated class
        for (Element e : roundEnv.getElementsAnnotatedWith(ClassAnnotation.class)) {
            // Skipped for brevity...
            // For each field
            for (Element ee : classElement.getEnclosedElements()) {
                // Skipped for brevity... (of course there's kind checking)
                TypeMirror fieldType = fieldElement.asType();
                TypeElement fieldTypeElement = (TypeElement) processingEnv.
                    getTypeUtils().asElement(fieldType);
            }
        }
        // Skipped for brevity
    }
}

I need to check whether a field's type is a class that is annotated with my annotation. Somehow I've got a TypeElement named fieldTypeElement, it may represent AnnotatedClass from someField or int from intIsNotAnnotated in the example. How to get @ClassAnnotation of AnnotatedClass of someField? I've tried fieldTypeElement.getAnnotation(ClassAnnotation.class) and fieldTypeElement.getAnnotationMirrors(), but it returns null and empty list respectively.

Upvotes: 5

Views: 3477

Answers (2)

kapex
kapex

Reputation: 29949

I think you are somehow getting the wrong TypeElement but unfortunatly that part of the code is missing.

This simple example works as expected:

processingEnv.getElementUtils().getTypeElement("AnnotatedClass").getAnnotationMirrors()

contains @ClassAnnotation.

To get the TypeElement of a field, you'll have to

  1. get the fields's type
  2. cast the type to DeclaredType
  3. get the declared type's element
  4. cast the element to TypeElement

The last step isn't necessary though to get an element's annotations:

Element field = // ... 
List<? extends AnnotationMirror> annotationMirrors =
    ((DeclaredType) field.asType()).asElement().getAnnotationMirrors();

The updated code should work, I've tested it and it runs fine. The error must be elsewhere. Some other things to check for:

  • Make sure the build is good, sometimes a build step fails and old code is used unnoticed
  • Check the RetentionPolicy of the annotation. None, CLASS or RUNTIME are fine but SOURCE won't work

Upvotes: 5

Kevin Bowersox
Kevin Bowersox

Reputation: 94429

Iterate through the Fields on the Class and check whether the type of each field contains the annotation. To get the type of the Field use the Field#getType method. From the provided pseudo code it appears you have access to the Fields.

Processor.java

public class Processor {

    public static void main(String[] args) {

        Class<?> clazz = AnotherAnnotatedClass.class;
        Field[] fields = clazz.getDeclaredFields();

        for(Field f:fields){
            if(f.getType().isAnnotationPresent(ClassAnnotation.class)){
                System.out.println(f.getName());
            }
        }
    }
}

ClassAnnotation.java

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ClassAnnotation {

}

AnnotatedClass.java

@ClassAnnotation
public class AnnotatedClass {

}

AnotherAnnotatedClass.java

@ClassAnnotation
public class AnotherAnnotatedClass {

    private AnnotatedClass annotatedClass;
    private int intIsNotAnnotated;
}

Upvotes: -2

Related Questions