Процессор аннотаций - Как получить класс, который он обрабатывает

Я пытаюсь написать пользовательский процессор Anntoation. Процессор аннотаций будет обрабатывать каждый файл класса во время компиляции для проверки аннотаций. Но как мне получить класс, который он обрабатывает в настоящее время? Я могу получить имя класса только в следующих кодах.

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 ответа

Решение

Вы не можете получить доступ к классу, который обрабатывает процессор аннотаций, поскольку класс еще не скомпилирован. Вместо этого Java предлагает аналогичный элемент 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
             }
        }
    }
}
  1. Это НЕ как AnnotationProcessing работает. Вы не можете получить Class<?> объект во время обработки, потому что классы, определение которых вы хотите , компилируются прямо сейчас! Если вы позвоните getClass() на неизвестный класс или использование Class<?> clazz = Class.forName("com.your.fancy.Class") ты получишь java.lang.ClassNotFoundException что совершенно нормально.
  2. Вам нужно использовать такие классы, как javax.lang.model.element.Element а также javax.lang.model.element.ExecutableElement описать / прочитать определения вашего класса.
  3. javax.lang.model.* имеет javax.lang.model.type.TypeMirror описывать классы, их поля, методы и т. д.
  4. Если вам нужно больше понимания, просто включите tools.jar из компилятора java (JAVA SDK), чтобы получить больше определений типов, которые используются во время компиляции. Но, скорее всего, вам не нужно добавлять эту зависимость jar!
  5. Ты получишь ClassNotFoundException даже после roundEnvironment.processingOver() это правда.
  6. КОРОТКО: ИСПОЛЬЗУЙТЕ TypeMirror во всех местах, где вы хотите использовать тип 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;
}
  • получить имя метода из объявления метода:
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;
}

иногда можно использовать: subElement.getEnclosingElement() поэтому вы можете получить родительский элемент, который может быть элементом класса, как вы хотите.

Другие вопросы по тегам