Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Annotation Processor - How to get the Class it is processing

I am trying to write a custom Anntoation processor. The annotation processor will process each class file at compile time to check annotations, But how am i able to get the class that it is currently processing? I am only able to get the class name in the following codes.

public class AnnotationProcessor extends AbstractProcessor {
  ......
    @Override
     public boolean process(Set<? extends TypeElement> annotations,
        RoundEnvironment roundEnv) {

     Set<? extends Element> rootE=roundEnv.getRootElements();
       for(Element e: rootE) {
        if(e.getKind()==ElementKind.CLASS) {
            String className= e.getSimpleName().toString();
            processingEnv.getMessager().printMessage( javax.tools.Diagnostic.Kind.WARNING,className, e); 
        }
     }
}
like image 980
user1004413 Avatar asked Aug 03 '13 15:08

user1004413


People also ask

What is Eclipse annotation processing?

The JDT-APT project provides plugins that add Java 5 annotation processing support to Eclipse. A Java annotation processor is a compiler plug-in that can gather information about source code as it is being compiled, generate additional Java types or other resource files, and post warnings and errors.


2 Answers

You are unable to access the Class the Annotation Processor is processing because the Class has not been compiled yet. Instead Java offers the analogous Elements api for reflection-style inspection of the input source.

The Element (which you found by using roundEnv.getRootElements()) has much more information about the class being compiled than just its name. A ton of useful information can be found by using the ElementVisitors:

http://docs.oracle.com/javase/6/docs/api/javax/lang/model/element/ElementVisitor.html http://docs.oracle.com/javase/6/docs/api/javax/lang/model/util/ElementKindVisitor6.html

Including the classes constructor, methods, fields, etc.

Here's how to use it:

public class AnnotationProcessor extends AbstractProcessor {
......
    @Override
     public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {

         Set<? extends Element> rootE=roundEnv.getRootElements();
         for(Element e: rootE) {
             for(Element subElement : e.getEnclosedElements()){
                 subElement.accept(new ExampleVisitor(), null); // implement ExampleVisitor
             }
        }
    }
}
like image 193
John Ericksen Avatar answered Sep 27 '22 22:09

John Ericksen


  1. This is NOT how AnnotationProcessing works. You cannot get a Class<?> object during processing becuase the classes that you want definition of are being compiled right NOW! If you call getClass() on an unknown class or use Class<?> clazz = Class.forName("com.your.fancy.Class") you'll get java.lang.ClassNotFoundException which is completely fine.
  2. You need to use classes such as javax.lang.model.element.Element and javax.lang.model.element.ExecutableElement to describe/read your class definitions.
  3. The javax.lang.model.* has javax.lang.model.type.TypeMirror to describe classes, their fields, methods etc.
  4. If you need more insight, just include tools.jar from the java compiler (JAVA SDK) to get more type definitions which are used during compilation. But most probably - you DON'T need to add this jar dependency!
  5. You'll get ClassNotFoundException even after roundEnvironment.processingOver() is true.
  6. IN SHORT: USE TypeMirror in all the places where you wanted to use the Class type.

Examples:

  • get list of methods from a class:
public static @Nonnull List getMethods(@Nonnull Element annotationElem, @Nonnull RoundEnvironment roundEnvironment) {
    List outList = new ArrayList();

    String simpleName = annotationElem.getSimpleName().toString();
    for (Element elem  : roundEnvironment.getRootElements())
        if (elem.getSimpleName().toString().equals(simpleName))
            for (Element methodDeclaration :elem.getEnclosedElements())
                if (methodDeclaration instanceof ExecutableElement)
                    outList.add((ExecutableElement)methodDeclaration);

    return outList;
}
  • get method name from method declaration:
public static TypeMirror getMethodFirstParam(@Nonnull ExecutableElement method, int n) {
     List parameters = ((ExecutableElement) method).getParameters();
     if (parameters != null && parameters.size() > 0)
         return parameters.get(n).asType();
     return null;
}
like image 24
kosiara - Bartosz Kosarzycki Avatar answered Sep 27 '22 23:09

kosiara - Bartosz Kosarzycki