2009-11-26 2 views
29

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

у меня есть:

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

Можете ли вы предоставить более подробную информацию о том, что вы пытаетесь выполнить? – Carl

+0

Как я уже сказал, я хочу использовать значение атрибута1, не повторяя его код –

+0

Это не эффективный метод программирования. Здесь нет преимущества наличия значений, заданных в аннотации, в отличие от того, чтобы они были установлены в конечных переменных внутри кода или были установлены в конечных статических переменных вне метода. – Jherico

ответ

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

Что-то вроде:

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

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

+0

не должно быть «MyValueType value1 = a.getAttribute1();» –

+0

или больше как «a.attribute()» – Bozho

+0

Конечно, должно быть. Спасибо, отредактировано – ChssPly76

19

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

  • Там - - нет способа получить текущий метод, например нет 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()); 
} 
+4

Существует способ получения текущего метода: либо Thread.currentThread(). getStackTrace() [2] .getMethodName() 'или' new Throwable(). FillInStackTrace(). GetStackTrace() [0].getMethodName() 'должен это делать. – ChssPly76

+1

+1 для упоминания Сохранение – basszero

+1

@ ChssPly76, построение stacktrace не является полностью надежным, поскольку в javadocs упоминается: «Некоторые виртуальные машины могут при некоторых обстоятельствах опустить один или несколько кадров стека из трассировки стека. В крайнем случае, виртуальной машине, которая не имеет информации о трассировке стека [...], разрешено возвращать массив нулевой длины из этого метода ». – gustafc

1

@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; 
    } 
} 

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

+3

У меня такое ощущение, что если вы на самом деле делаете это в производственном коде, он призывает Великих Старейшин, чтобы поглотить вашу душу! –

+0

@Skip Head - почему? Здесь есть две вещи: (1) индекс массива ** в теории ** может отличаться от 2 на некоторых JVM, но это легко обойти, пройдя весь след; (2) это не будет работать для перегруженных методов; вы можете сделать черную магию с javassist, чтобы угадать правильный, основанный на номере строки, но это действительно немного. Другое дело, что, тем не менее, он отлично работает - как вы думаете, работают трассировки стека? – ChssPly76

+0

@ ChssPly76: Не нужно ходить по всему следу. Метод трассировки начинается сверху и проходит до тех пор, пока не найдет себя. А вызывающий - следующий. – alphazero

0

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

Thread.currentThread().getStackTrace()[1].getClassName().toString()+\".\"+Thread.currentThread().getStackTrace()[1].getMethodName().toString() 
Смежные вопросы