Как выполнить метод с тем же именем из разных аннотаций

Хотя мой вопрос связан с обработкой аннотаций, мой вопрос больше связан с аннотациями Java.

Я писал код, пока не понял, что не знаю, как что-то реализовать.

Программа использует обработку аннотаций, я пытаюсь получить значение нескольких аннотаций JAX-RS, возьмем для примера @PathParam и @QueryParam. Обе аннотации содержат абстрактный метод value().


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

@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {

    for(Element element : roundEnv.getElementsAnnotatedWith(PathParam.class)) {
        PathParam parameter = element.getAnnotation(PathParam.class);
        String value = parameter.value();

        // Process data & more program code.
    }

    for(Element element : roundEnv.getElementsAnnotatedWith(QueryParam.class)) {
        QueryParam parameter = element.getAnnotation(QueryParam.class);
        String value = parameter.value();

        // Process data & more program code.
    }

    // Etc... do the same for other JAX-RS annotations.

    return true;
}

Я знаю, что с абстрактными классами вы можете делать следующее:

abstract class Animal { 
    abstract String name();
}

class Dog extends Animal {
    public String name() {
        return "Dog";
    }
}

class Cat extends Animal {
    public String name() {
        return "Cat";
    }
}

Animal animal = new Cat();
System.out.println(animal.name()); // Prints 'Cat'

animal = new Dog();
System.out.println(animal.name()); // Prints 'Dog'

Но я не уверен, как сделать то же самое с помощью аннотации, поскольку нет суперкласса, к которому он мог бы быть приведен. Я предполагаю, что это должно быть что-то вроде этого:

ArrayList<Class<? extends Annotation>> annotationsToCheck = 
        new ArrayList<>(Arrays.asList(PathParam.class, QueryParam.class));

for(Class<? extends Annotation> annotationToCheck : annotationsToCheck) {
    for(Element element : roundEnv.getElementsAnnotatedWith(annotationToCheck)) {

        // Somehow cast it to something so that the value() method can be accessed

        // Process data & more program code.

    }

}

Я чувствую, что я близок, но я просто не могу понять это. Есть ли хороший способ решить мою проблему?


person Mark    schedule 12.10.2018    source источник
comment
Извините, но я не вижу деклараций Java interface в этом коде. Подсказка: _2 _ - это аннотация, а не интерфейс. List будет примером интерфейса. .   -  person Andreas    schedule 12.10.2018
comment
@PathParam и @QueryParam в javax.ws.rs - это интерфейсы, если я неправильно понял, дайте мне знать.   -  person Mark    schedule 12.10.2018
comment
comment
Ой, я обновлю свой вопрос. Спасибо.   -  person Mark    schedule 12.10.2018
comment
Вы пробовали getElementsAnnotatedWithAny​(Set.of(PathParam.class, QueryParam.class))?   -  person Andreas    schedule 12.10.2018
comment
Хорошее предложение! Однако даже если бы мне пришлось перейти на Java 9, я бы все равно застрял с Set<? extends Element>, который возвращает эта функция. Я все еще не могу получить доступ к методу value() без преобразования / проверки, @PathParam или @QueryParam.   -  person Mark    schedule 12.10.2018
comment
Конечно, вы не можете получить доступ к value() без предварительного преобразования, потому что, что касается Java, Element может иметь обе аннотации одновременно, с разными значениями, и эти значения имеют разное значение в зависимости от того, в какой аннотации он включен, поэтому сначала у вас есть для обозначения аннотации. Как вы можете правильно интерпретировать результат value(), не зная конкретной аннотации?   -  person Andreas    schedule 12.10.2018
comment
Да, однако, если вы посмотрите на последний блок кода, я сначала перебираю все элементы, помеченные знаком @PathParam, а затем @QueryParam. Поскольку он получает все Element объекты с аннотациями annotationToCheck, вы знаете, какая аннотация в настоящее время используется для получения элементов. Мой вопрос заключался в том, есть ли способ написать его таким образом, чтобы я мог вызвать метод value() переменной element любой аннотации без их преобразования.   -  person Mark    schedule 13.10.2018


Ответы (1)


В Java 9+ кастинг не требуется:

for (Element element : roundEnv.getElementsAnnotatedWithAny​(Set.of(PathParam.class,
                                                                   QueryParam.class))) {
    PathParam pathParam = element.getAnnotation(PathParam.class);
    if (pathParam != null) {
        String value = pathParam.value();
        // Process @PathParam value
    }
    QueryParam queryParam = element.getAnnotation(QueryParam.class);
    if (queryParam != null) {
        String value = queryParam.value();
        // Process @QueryParam value
    }
}

Или, если вы ожидаете только одного из них:

for (Element element : roundEnv.getElementsAnnotatedWithAny​(Set.of(PathParam.class,
                                                                   QueryParam.class))) {
    String value = null;
    PathParam pathParam = null;
    QueryParam queryParam = null;
    if ((pathParam = element.getAnnotation(PathParam.class)) != null) {
        value = pathParam.value();
    } else if ((queryParam = element.getAnnotation(QueryParam.class)) != null) {
        value = queryParam.value();
    }
    // Process value. Exactly one of pathParam and queryParam will be non-null
}
person Andreas    schedule 12.10.2018
comment
Не совсем так, как я себе представляла, но все чисто! Спасибо ???? - person Mark; 13.10.2018