Как проверить, есть ли у параметра текущего метода аннотация и получить значение этого параметра в Java? - PullRequest
9 голосов
/ 29 августа 2011

Рассмотрим этот код:

public example(String s, int i, @Foo Bar bar) {
  /* ... */
}

Я хочу проверить, есть ли у метода аннотация @Foo и получить аргумент или вызвать исключение, если аннотация @Foo не найдена.

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

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

class Util {

    private Method getCurrentMethod() {
        try {
            final StackTraceElement[] stes = Thread.currentThread().getStackTrace();
            final StackTraceElement ste = stes[stes.length - 1];
            final String methodName = ste.getMethodName();
            final String className = ste.getClassName();   
            final Class<?> currentClass = Class.forName(className);
            return currentClass.getDeclaredMethod(methodName);
        } catch (Exception cause) {
            throw new UnsupportedOperationException(cause);
        }  
    }

    private Object getArgumentFromMethodWithAnnotation(Method method, Class<?> annotation) {
        final Annotation[][] paramAnnotations = method.getParameterAnnotations();    
            for (Annotation[] annotations : paramAnnotations) {
                for (Annotation an : annotations) {
                    /* ... */
                }
            }
    }

}

Это правильный подход или есть лучший? Как будет выглядеть код внутри цикла forach? Я не уверен, что понял, что на самом деле возвращает getParameterAnnotations ...

Ответы [ 3 ]

6 голосов
/ 29 августа 2011

Внешний для петли

for (Annotation[] annotations : paramAnnotations) {
   ...
}

следует использовать явный счетчик, иначе вы не знаете, какой параметр вы сейчас обрабатываете

final Annotation[][] paramAnnotations = method.getParameterAnnotations();
final Class[] paramTypes = method.getParameterTypes();
for (int i = 0; i < paramAnnotations.length; i++) {
    for (Annotation a: paramAnnotations[i]) {
        if (a instanceof Foo) {
            System.out.println(String.format("parameter %d with type %s is annotated with @Foo", i, paramTypes[i]);
        }
    }
}

Также убедитесь, что ваш тип аннотации помечен @Retention(RetentionPolicy.RUNTIME)

Из вашего вопроса не совсем понятно, что вы пытаетесь сделать. Мы согласны на разницу формальных параметров и фактических аргументов:

void foo(int x) { }

{ foo(3); }

где x - параметр, а 3 - аргумент?

Невозможно получить аргументы методов через отражение. Если это вообще возможно, вам придется использовать пакет sun.unsafe. Я не могу вам много рассказать об этом.

4 голосов
/ 29 августа 2011

getParameterAnnotations возвращает массив с длиной, равной количеству параметров метода.Каждый элемент в этом массиве содержит массив аннотаций для этого параметра.
Таким образом, getParameterAnnotations()[2][0] содержит первую ([0]) аннотацию третьего ([2]) параметра.

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

private boolean isAnyParameterAnnotated(Method method, Class<?> annotationType) {
    final Annotation[][] paramAnnotations = method.getParameterAnnotations();    
    for (Annotation[] annotations : paramAnnotations) {
        for (Annotation an : annotations) {
            if(an.annotationType().equals(annotationType)) {
                return true;
            }
        }
    }
    return false;
}
3 голосов
/ 29 августа 2011

Если вы ищете аннотации к методу, вы, вероятно, захотите method.getAnnotations() или method.getDeclaredAnnotations().

Вызов method.getParameterAnnotations() дает вам аннотации к формальным параметрам метода, а не к самому методу.

Оглядываясь назад на заголовок вопроса, я подозреваю, что вы ищете аннотации к параметрам, которые я не читал в содержании вопроса. Если это так, ваш код выглядит хорошо.

См. Метод Javadoc и AnnotatedElement Javadoc .

...