Получение типа поля без аннотаций в процессоре аннотаций - PullRequest
1 голос
/ 20 января 2020

Я некоторое время боролся с этим, полагаясь на различные тайные приведения и манипуляции с toString, чтобы заставить его работать, но должен быть правильный способ сделать это.

У меня есть процессор аннотаций, который выглядит следующим образом:

@SupportedAnnotationTypes("processor.EchoFields")
@SupportedSourceVersion(SourceVersion.RELEASE_11)
public class TestProcessor extends AbstractProcessor {
    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        roundEnvironment.getElementsAnnotatedWith(EchoFields.class)
                .stream()
                .filter(e -> e.getKind() == ElementKind.CLASS)
                .map(TypeElement.class::cast)
                .forEach(this::echoFields);
        return false;
    }

    private void echoFields(TypeElement element) {
        log("Fields of class %s", element);
        element.getEnclosedElements().stream()
                .filter(e -> e.getKind() == ElementKind.FIELD)
                .map(VariableElement.class::cast)
                .forEach(this::echoField);
    }

    private void echoField(VariableElement element) {
        log("\tField %s of type %s", element.getSimpleName().toString(), element.asType().toString());
        for (AnnotationMirror annotationMirror : element.getAnnotationMirrors()) {
            log("\t\t%s", annotationMirror);
        }
    }

    private void log(String format, Object... parameters) {
        processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, String.format(format, parameters));
    }

}

При запуске в моем тестовом классе это выглядит так:

@EchoFields
public class Pojo {

    @TypeAnnotation
    @FieldAnnotation
    private List<String> aListOfStrings;
}

( @ TypeAnnotation и @ FieldAnnotation имеют цели TYPE (_USE) и FIELD соответственно)

Я получаю следующий вывод:

Note: Fields of class consumer.Pojo
Note:   Field aListOfStrings of type @processor.TypeAnnotation java.util.List<java.lang.String>
Note:           @processor.FieldAnnotation

В то время как то, что я хочу, это:

Note: Fields of class consumer.Pojo
Note:   Field aListOfStrings of type java.util.List<java.lang.String>
Note:           @processor.TypeAnnotation
Note:           @processor.FieldAnnotation

С важной частью java.util.List<java.lang.String> без @processor.TypeAnnotation - Листинг @processor.TypeAnnotation с аннотациями это просто бонус, а не то, что мне нужно .

Хотя я не могу найти какой-либо способ сделать это. Каждый раз, когда я нахожу что-то, что удаляет аннотацию, я также теряю параметры типа (java.lang.String). Я изучал классы, реализующие API обработки аннотаций, и там определенно есть методы, которые делают то, что я хочу, - но я не могу найти способ вызвать их через API publi c, и я не хочу полагаться на детали реализации (тем более что я получил совершенно разные реализации, когда попробовал это на JDK 8).

Есть работающий проект Gradle на https://github.com/Raniz85/processor-test, просто клонируйте и запустите ./gradlew build

1 Ответ

2 голосов
/ 20 января 2020

Поскольку TypeAnnotation помечен как TYPE + TYPE_USE (и обратите внимание, что TYPE не имеет отношения к данной проблеме), а не FIELD, он вообще не является аннотацией для поля, но фактически относится к объявленному типу поле. Вы можете помещать аннотации TYPE_USE и в другие вещи, например в локальные переменные, но вы не можете читать их из обычного процессора аннотаций. From Как получить доступ к аннотации TypeUse через AnnotationProcessor :

Аннотации TYPE_USE немного сложны, потому что компилятор обрабатывает их иначе, чем аннотации «старого использования».

Итак, как вы правильно заметили, они не передаются процессору аннотаций, и ваш метод process () никогда их не получит.

Не зная конкретно, какую проблему вы пытаетесь решить, это Трудно сказать, действительно ли вам нужен TYPE_USE, или вы просто экспериментируете с различными возможными целями, которые может иметь аннотация. Возможно, вы просто хотите использовать FIELD вместо этого здесь, поскольку вы пишете процессор аннотаций (который пересекает ваш API, а не сам исходный код, поэтому вы пропустите любой TYPE_USE в локальных переменных, и т. Д. c).

-

Кроме того, будьте очень осторожны с использованием TypeMirror.toString () или Element.toString (), в некоторых средах они не будут отображать то, что вы ожидаете. Либо используйте тип Name, либо что-то вроде иерархии TypeName javapoet.

...