Предотвращение добавления аннотации Java в конечное поле - PullRequest
3 голосов
/ 30 октября 2019
@MyAnnotation
final Integer value;

Можно ли настроить пользовательскую аннотацию MyAnnotation таким образом, чтобы это приводило к ошибке времени компиляции, указанной выше, но не было ошибки времени компиляции при добавлении в неконечное поле? (независимо от уровня доступа).

Справочная информация: в нашем коде у нас есть специальная аннотация, которая запускает модификацию посредством отражения от внешнего класса, и это не может быть сделано для конечных полей, поэтому мы хотели бы предупредитьпользователи аннотации во время компиляции (в настоящее время у нас есть проверка во время выполнения, которая выдаст исключение).

1 Ответ

0 голосов
/ 31 октября 2019

Одной из опций является процессор аннотаций . Например, если у вас есть следующая аннотация:

package com.example;

import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME) // must be at least SOURCE
@Target(ElementType.FIELD)
public @interface Foo {}

, то следующее будет выдавать ошибку, если в поле final присутствует @Foo:

package com.example;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;
import java.util.Set;

@SupportedAnnotationTypes("com.example.Foo")
@SupportedSourceVersion(SourceVersion.RELEASE_13) // or whatever version you support
public class FooProcessor extends AbstractProcessor {

  @Override
  public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
    if (!annotations.isEmpty()) {
      // This processor is only declared to process one annotation
      TypeElement foo = annotations.iterator().next();

      for (Element element : roundEnv.getElementsAnnotatedWith(foo)) {
        for (AnnotationMirror mirror : element.getAnnotationMirrors()) {
          if (mirror.getAnnotationType().asElement().equals(foo)
              && element.getModifiers().contains(Modifier.FINAL)) {
            // processingEnv is a protected field of AbstractProcessor
            processingEnv.getMessager()
                .printMessage(Kind.ERROR, "Field cannot be final.", element, mirror);
            break;
          }
        }
      }
    }
    return true;
  }
}

ВПриведенный выше код Я использовал только API модели (например, TypeElement) для ссылки на аннотацию Foo. Обратите внимание, однако, что API процессора аннотаций позволяет использовать класс аннотации (например, Foo.class), если аннотация видима (т. Е. Ваш процессор зависит от аннотации). Использование API класса может быть более простым в использовании, более легким для размышления и более легким для чтения - используйте его, если ваш класс аннотаций видим для вашего класса процессора.


Затем вам нужно будет сказать javac использовать процессор аннотаций. См. спецификацию инструмента для получения дополнительной информации;в частности, обратите внимание на стандартные опции --processor-path, --processor-module-path, -processor и -proc, а также раздел по обработке аннотаций.

Обратите внимание, что вы не сможетедля обеспечения использования вашего процессора аннотаций.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...