Search code examples
javaannotation-processing

How to find annotated methods in TypeElement?


Assume that I have this class:

public class MyClass extends Ancestor{

    @MyAnnotation
    void doSomething(){
    }

    @MyAnnotation
    void doAnotherthing(String[] args){
    }

}

public class Ancestor{

    @MyAnnotation
    void doFirst(){
    }
}

In my annotation processor I have a TypeElement instance of MyClass.

How can I find annotated methods with @MyAnnotation in both MyClass and its ancestor?

( I know it's possible with RoundEnvironment but i don't want to use it)


Solution

  • static Set<Element> getAnnotatedElements(
        Elements elements,
        TypeElement type,
        Class<? extends Annotation> annotation)
    {
        Set<Element> found = new HashSet<Element>();
        for (Element e : elements.getAllMembers(type)) {
            if (e.getAnnotation(annotation) != null)
                found.add(e);
        }
        return found;
    }
    

    Of course, you could also filter for e.g. only methods with e.getKind() == ElementKind.METHOD.

    Elements is necessary because you want to find the method on the superclass as well. It's possible to do without it, but it's really much more work than necessary.

    See Elements#getAllMembers, Element#getAnnotation and also TypeElement#getEnclosedElements.

    I know it's possible with RoundEnvironment but i don't want to use it

    From the documentation for RoundEnvironment#getElementsAnnotatedWith:

    Only package elements and type elements included in this round of annotation processing, or declarations of members, constructors, parameters, or type parameters declared within those, are returned.

    So actually, RoundEnvironment may or may not work for finding annotated elements in general, depending on what you're doing. The methods on RoundEnvironment are specifically useful for finding the elements which are annotated with the annotation you are processing.

    Also of course it's pretty terrible if you want to reduce the search to some smaller scope, in your case, MyClass. RoundEnvironment finds everything. If we wanted to, say, find methods that some particular class Bar overrides from its superclass Foo, RoundEnvironment is very awkward for that. We'd have to find all methods that override anything, then use getEnclosingElement() to find the ones that belong to Bar.

    If, for example, you were writing an annotation processor for MyAnnotation, then it would make much more sense to use RoundEnvironment, because annotations are not necessarily processed in a single round. Searching for annotations yourself instead of going through RoundEnvironment could result in you finding annotations that you've already processed on a prior round.