注解处理器 - 如何获取它正在处理的类

16

我正在尝试编写自定义注解处理器。 注解处理器将在编译时处理每个类文件以检查注解, 但是我如何能够获取它当前正在处理的类? 下面的代码只能获取类名。

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); 
        }
     }
}
3个回答

15

由于类还未编译,您无法访问注解处理器正在处理的类。Java提供了类似反射的Elements API来检查输入源。

元素(您可以使用roundEnv.getRootElements()找到它)具有关于编译的类的更多信息,而不仅仅是名称。通过使用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

包括类的构造函数、方法、字段等。

以下是如何使用它:

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
             }
        }
    }
}

你说:“……编译的类有比名称更多的信息”,但是你如何获取类名? - Matthias
类名将在Element.getSimpleName()中。http://docs.oracle.com/javase/7/docs/api/javax/lang/model/element/Element.html#getSimpleName%28%29 - John Ericksen

13
  1. 不是注解处理的工作方式。在处理期间,您不能获取Class<?>对象,因为您想要定义的类正在编译中!如果您在未知类上调用getClass()或使用Class.forName("com.your.fancy.Class"),您将得到java.lang.ClassNotFoundException,这完全没有问题。
  2. 您需要使用诸如javax.lang.model.element.Elementjavax.lang.model.element.ExecutableElement之类的类来描述/读取您的类定义。
  3. javax.lang.model.*javax.lang.model.type.TypeMirror来描述类、它们的字段、方法等。
  4. 如果您需要更多信息,只需包括Java编译器(JAVA SDK)中的tools.jar以获取更多在编译期间使用的类型定义。但最可能 - 您不需要添加此jar依赖项!
  5. 即使在roundEnvironment.processingOver()返回true后,您仍将收到ClassNotFoundException
  6. 简而言之:在所有您想使用Class类型的地方都使用TypeMirror。

示例:

  • 从类中获取方法列表:
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;
}
  • 从方法声明获取方法名:
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;
}

annotationElem是否是roundEnvironment的根元素? - eastwater

0
有时候你可以使用:subElement.getEnclosingElement(),这样你就可以获取父元素,它可能是你想要的类元素。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接