Как разрешить только классы с аннотацией в параметрах метода в Java? - PullRequest
0 голосов
/ 04 апреля 2020

Предположим, у меня есть аннотация @MyAnnotation и два класса:

@MyAnnotation
class Foo {
}

class Bar {
}

и некоторый метод, которому нужен класс в качестве параметра

someMethod(Class<?> klass)

Можно ли ограничить параметр someMethod только для классов, которые отмечены @MyAnnotation? Я имею в виду:

someMethod(Foo.class) //Must work
someMethod(Bar.class) //Compiler error

Если да, то как это сделать?

Ответы [ 2 ]

1 голос
/ 05 апреля 2020

Да, это возможно.

Как правило, если свойство выражается с помощью аннотации, вам необходимо использовать процессор аннотаций.

Вот полный пример того, что использует Checker Framework .

Файл SO61029446.java:

public class SO61029446 {
  void someMethod(Class<? extends @MyAnnotation Object> klass) {}

  void client() {
    someMethod(Foo.class); // Must work
    someMethod(Bar.class); // Compiler error
  }
}

@MyAnnotation
@SuppressWarnings("subtyping")
class Foo {}

class Bar {}

Файл MyAnnotation.java:

@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
@SubtypeOf(UnknownMyAnnotation.class)
@interface MyAnnotation {}

@DefaultQualifierInHierarchy
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
@SubtypeOf({})
@interface UnknownMyAnnotation {}

Теперь запустите эти команды (после установки Checker Framework):

javacheck MyAnnotation.java
javacheck -g SO61029446.java -processor org.checkerframework.common.subtyping.SubtypingChecker -Aquals=MyAnnotation,UnknownMyAnnotation SO61029446.java

Вывод второй команды:

SO61029446.java:11: error: [argument.type.incompatible] incompatible types in argument.
    someMethod(Bar.class); // Compiler error
                  ^
  found   : @UnknownMyAnnotation Class<@UnknownMyAnnotation Bar>
  required: @UnknownMyAnnotation Class<? extends @MyAnnotation Object>

Компилятор пожаловался на недопустимый вызов, но разрешил законный вызов, просто как вы просили.

Несколько замечаний:

  • Команда javacheck такая же, как описано в Checker Framework Manual .
  • Там являются двумя javacheck командами, потому что первая делает аннотации доступными для пути к классам для второй.
  • Аннотация @SuppressWarnings("subtyping") к классу Foo может не потребоваться в зависимости от вашего фактического кода. (Это игрушечный пример.)
  • Ответ Слоу начинается с первого предложения «Нет, это невозможно.», Что является неверным . Другой подход Слава к решению проблемы без аннотаций не является плохим (в некоторых отношениях это лучше, потому что он использует только компилятор Java без какого-либо дополнительного инструмента), но он не отвечает на этот вопрос об использовании аннотаций.
1 голос
/ 04 апреля 2020

Нет, это невозможно. Тип параметра Class<?> не может описывать наличие или отсутствие аннотации и, следовательно, не может обеспечить наличие аннотации. Я думаю, что лучшее, что вы можете здесь сделать, это использовать интерфейс маркера. Например, если у вас есть следующее:

interface Marker {}
class Foo implements Marker {}
class Bar {}

Тогда вы можете определить свой метод следующим образом:

void someMethod(Class<? extends Marker> klass) {}

И вы сможете передать Foo.class в качестве аргумента но не Bar.class. Предостережение в этом подходе заключается в том, что любой класс, который наследуется от Foo, также может быть передан в качестве аргумента. Это может отличаться от предполагаемого вами поведения, так как аннотации к классам не наследуются, если только мета-аннотируются с помощью @Inherited. Другое предостережение заключается в том, что реализация интерфейса становится частью API класса (т. Е. Publi c contract). То же самое не верно при размещении аннотации, если указанная аннотация не помечена мета-аннотацией @Documented.

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