2009-11-26 157 views
29

如何檢索註釋方法上的註釋值?檢索Java註釋屬性

我:

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

你能提供更多關於你想要完成的細節嗎? – Carl 2009-11-26 19:16:50

+0

正如我所說的,我想使用attribute1的值,而不必在代碼 – 2009-11-26 19:21:17

+0

上重複它,這不是一個真正有效的編程方法。在註釋中設置值與在代碼內部設置最終變量或在方法外部的最終靜態變量中設置值相比,沒有任何優勢。 – Jherico 2009-11-26 22:38:31

回答

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();」 – 2009-11-26 19:27:15

+0

或更多像「a.attribute()' – Bozho 2009-11-26 19:35:35

+0

當然應該有。謝謝,編輯 – ChssPly76 2009-11-26 19:40:03

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 2009-11-26 19:48:23

+1

+1提醒保留 – basszero 2009-11-26 19:53:24

+1

@ ChssPly76,構建堆棧跟蹤並不完全可靠,因爲javadoc提到:「某些虛擬機在某些情況下可能會忽略堆棧跟蹤中的一個或多個堆棧幀,在極端情況下,一個沒有堆棧跟蹤信息的虛擬機被允許從這個方法返回一個零長度的數組。 – gustafc 2009-11-27 07:21:03

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

[編輯:信用卡/感謝亞歷山大Priymak爲察覺在main()錯誤]

+3

我有一種感覺,如果你真的在生產代碼中做到這一點,它會召喚大老頭去吞噬你的靈魂! – 2009-11-26 21:14:14

+0

@Skip Head - 爲什麼?這裏需要注意兩點 - (1)理論上的數組索引**在某些JVM上可能不同於2,但通過遍歷整個跟蹤很容易解決; (2)這不適用於重載的方法;你可以用javassist做一些黑魔法來根據行號猜測正確的那個,但這真的有點不確定。除此之外,它的工作原理是完美的 - 你如何看待棧跟蹤工作? – ChssPly76 2009-11-26 21:26:20

+0

@ ChssPly76:無需走完整個痕跡。跟蹤方法從頂部開始,直到找到它自己。而來電是下一個。 – alphazero 2009-11-26 22:26:13

0

要獲得目前的方法,請嘗試使用此代碼:

Thread.currentThread().getStackTrace()[1].getClassName().toString()+\".\"+Thread.currentThread().getStackTrace()[1].getMethodName().toString()