Получить атрибут аннотации Java

Как я могу получить значение аннотации для аннотированного метода??

У меня есть:

@myAnnotation(attribute1 = value1, attibute2 = value2)
public void myMethod()
{
  //I want to get value1 here
}

person Diego Dias    schedule 26.11.2009    source источник
comment
Можете ли вы предоставить более подробную информацию о том, чего вы пытаетесь достичь?   -  person Carl    schedule 26.11.2009
comment
Как я уже сказал, я хочу использовать значение атрибута1, не повторяя его в коде.   -  person Diego Dias    schedule 26.11.2009
comment
Это не очень эффективный метод программирования. Здесь нет никакого преимущества в том, что значения устанавливаются в аннотации, а не в переменных final внутри кода или в статических переменных final вне метода.   -  person Jherico    schedule 27.11.2009


Ответы (4)


  1. Получите экземпляр Method.
  2. Получить аннотацию.
  3. Получите значение атрибута аннотации.

Что-то типа:

Method m = getClass().getMethod("myMethod");
MyAnnotation a = m.getAnnotation(MyAnnotation.class);
MyValueType value1 = a.attribute1();

Конечно, вам нужно поймать/обработать соответствующие исключения. Вышеприведенное предполагает, что вы действительно извлекаете метод из текущего класса (в противном случае замените getClass() на Class.forName()), а рассматриваемый метод является общедоступным (используйте getDeclaredMethods(), если это не так).

person ChssPly76    schedule 26.11.2009
comment
разве это не должно быть MyValueType value1 = a.getAttribute1(); - person DJ.; 26.11.2009
comment
Что касается шага 1, получите экземпляр метода, используя следующее решение: stackoverflow.com/a/5891326/435605 - person AlikElzin-kilaka; 27.04.2015
comment
Обратите внимание, что имя метода может быть изменено путем обфускации или даже оптимизации, специфичной для компилятора, в конце концов, абсолютно не гарантируется, что на него будут ссылаться по имени во время выполнения. - person Thomas; 21.07.2016

Две важные вещи:

  • Нет способа получить текущий метод, например. нет getMethod(), такого как getClass(). Следовательно, метод, обращающийся к своей собственной аннотации, должен знать свое имя.
  • Для политики хранения аннотации должно быть установлено значение RUNTIME, чтобы вы могли получить доступ к аннотации во время выполнения. По умолчанию используется время компиляции, что означает, что аннотации доступны в файле класса, но недоступны во время выполнения с использованием отражения.

Полный пример:

@Retention(RetentionPolicy.RUNTIME)
public static @interface MyAnnotation {
    String value1();

    int value2();
}

@Test
@MyAnnotation(value1 = "Foo", value2 = 1337)
public void testAnnotation() throws Exception {
    Method[] methods = getClass().getMethods();
    Method method = methods[0];
    assertEquals("testAnnotation", method.getName());
    MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
    assertEquals("Foo", annotation.value1());
    assertEquals(1337, annotation.value2());
}
person mhaller    schedule 26.11.2009
comment
Есть способ получить текущий метод. Это должен сделать либо Thread.currentThread().getStackTrace()[2].getMethodName(), либо new Throwable().fillInStackTrace().getStackTrace()[0].getMethodName(). - person ChssPly76; 26.11.2009
comment
@ChssPly76, построение трассировки стека не совсем надежно, как упоминается в javadocs: некоторые виртуальные машины могут при некоторых обстоятельствах пропускать один или несколько кадров стека из трассировки стека. В крайнем случае, виртуальной машине, у которой нет информации о трассировке стека [...], разрешается возвращать массив нулевой длины из этого метода. - person gustafc; 27.11.2009
comment
Получите экземпляр метода, используя следующее решение: stackoverflow.com/a/5891326/435605 - person AlikElzin-kilaka; 27.04.2015

Чтобы получить текущий метод, попробуйте использовать этот код:

Thread.currentThread().getStackTrace()[1].getClassName().toString()+\".\"+Thread.currentThread().getStackTrace()[1].getMethodName().toString()
person s s    schedule 19.01.2017

@mhaller: слишком длинно для комментария к твоему посту. Очевидно, что для работы с перегруженными методами потребуется дальнейшее уточнение, но это не невозможно.:

import java.lang.reflect.Method;

public class Hack {
    public static void main (String[] args) {
        (new Hack()).foobar();
    }
    public void foobar () {
        Method here = getCurrentMethod(this);
        System.out.format("And here we are: %s\n", here);
    }
    public static final Method getCurrentMethod(Object o) {
        String s = Thread.currentThread().getStackTrace()[2].getMethodName();
        Method cm = null;
        for(Method m : o.getClass().getMethods()){
            if(m.getName().equals(s)){
                cm = m; break;
            }
        }
        return cm;
    }
}

[править: кредит/спасибо Александру Приймаку за обнаружение ошибки в main()]

person alphazero    schedule 26.11.2009
comment
У меня такое ощущение, что если вы действительно сделаете это в рабочем коде, это вызовет Великих Древних, чтобы поглотить вашу душу! - person Skip Head; 27.11.2009
comment
@Пропустить голову - почему? Здесь нужно быть осторожным с двумя вещами: (1) индекс массива теоретически может отличаться от 2 на некоторых JVM, но это легко обойти, пройдя всю трассировку; (2) это не будет работать для перегруженных методов; вы можете использовать черную магию с javassist, чтобы угадать правильный на основе номера строки, но это действительно несколько сомнительно. Кроме того, это работает отлично - как, по-вашему, работает трассировка стека? - person ChssPly76; 27.11.2009
comment
@ChssPly76: Нет необходимости проходить всю трассу. Метод трассировки начинается сверху и проходит, пока не найдет себя. А звонящий следующий. - person alphazero; 27.11.2009
comment
@alphazero - вы могли бы так подумать, но нет :-) То есть, это обычно так, но это нигде не указано AFAIK, что означает, что вы можете иметь реализацию JVM, которая ведет себя по-другому (например, рассматриваемый метод может быть во втором или даже первом аргументе массива трассировки стека) - person ChssPly76; 27.11.2009