2013-04-30 57 views
41

我正在嘗試做一些Java註釋魔術。我必須說,我仍然趕上註釋技巧,並且某些事情對我來說還不是很清楚。如何創建註釋的實例

所以...我有一些註釋類,方法和字段。我有一個方法,它使用反射來對類進行一些檢查,並向類中注入一些值。這一切工作正常。

但是,我現在面臨的情況是,我需要一個註釋的實例(這麼說)。所以...註釋不像常規的接口,你不能做一個類的匿名實現。我知道了。我在這裏看過一些關於類似問題的帖子,但我似乎無法找到我正在尋找的答案。

我基本上喜歡得到和註釋的實例,並能夠使用反射(我想)設置它的一些領域。有沒有辦法做到這一點?

+1

您無法實例化或修改註釋。當您運行代碼時,它們已經存在。你只能檢索它們。你可以給你一些你想要做的代碼示例嗎? – NilsH 2013-04-30 12:21:10

+0

你嘗試過getAnnotation()java.lang.Class中/ java.lang.reflect.Method中可用 – 2013-04-30 12:21:52

+0

您是否嘗試過的getClass()。getAnnotations()? – prasanth 2013-04-30 12:23:02

回答

48

好吧,它顯然沒有那麼複雜。 真的!

正如指出的同事,你可以簡單地創建註釋(像任何接口)的匿名情況下是這樣的:

MyAnnotation:

public @interface MyAnnotation 
{ 

    String foo(); 

} 

調用代碼:

class MyApp 
{ 
    MyAnnotation getInstanceOfAnnotation(final String foo) 
    { 
     MyAnnotation annotation = new MyAnnotation() 
     { 
      @Override 
      public String foo() 
      { 
       return foo; 
      } 

      @Override 
      public Class<? extends Annotation> annotationType() 
      { 
       return MyAnnotation.class; 
      } 
     }; 

     return annotation; 
    } 
} 

Credits to Martin Grigorov

+0

嗯,看來你還需要實現['annotationType'](http://docs.oracle.com/javase/7/docs/api/java/lang/annotation/Annotation.html# annotationType())。大概這隻會返回'MyAnnotation.class'。 – 2013-04-30 15:14:47

+0

有趣的事情要注意。實際上,我讓IDE生成了這些方法,並沒有注意到它也實現了。它留下來返回'null'並且工作。我已經將它設置爲註釋的類類型,但我不確定它應該是什麼。 – carlspring 2013-04-30 15:23:38

+0

我猜這是註釋查找功能所必需的。對於您的具體情況,可能不需要,但似乎更正確地返回正確的事情(因爲您必須執行它)。 – 2013-04-30 15:26:29

7

您可以使用Hibernate Validator項目(免責聲明:我是後者的提交者)的註釋代理,如this onethis one

5

您可以使用sun.reflect.annotation.AnnotationParser.annotationForMap(Class, Map)

public @interface MyAnnotation { 
    String foo(); 
} 

public class MyApp { 
    public MyAnnotation getInstanceOfAnnotation(final String foo) { 
     MyAnnotation annotation = AnnotationParser.annotationForMap(
      MyAnnotation.class, Collections.singletonMap("foo", "myFooResult")); 
    } 
} 

下行:從sun.*類是在以後的版本中的更改(allthough因爲Java 5的這種方法存在具有相同簽名),不適用於所有的Java實現,見this discussion

如果這是一個問題:您可以使用您自己的InvocationHandler創建一個通用代理 - 這正是AnnotationParser在內部爲您所做的。或者您使用您自己的MyAnnotation的定義here。在這兩種情況下,您都應該記住實施annotationType()equals()hashCode(),因爲結果是專門爲java.lang.Annotation記錄的。

7

代理方式,如Gunnar's answer建議在GeAnTyRef已經實現:

Map<String, Object> annotationParameters = new HashMap<>(); 
annotationParameters.put("name", "someName"); 
MyAnnotation myAnnotation = TypeFactory.annotation(MyAnnotation.class, annotationParameters); 

這將產生一個註解相當於你從得到什麼:生成此

@MyAnnotation(name = "someName") 

Annotation實例方式將與通常由Java生成的方式相同,並且它們的hashCodeequals已正確實現兼容性,所以沒有類似於direc的離奇警告如接受的答案中那樣實例化註釋。實際上,JDK內部使用相同的方法:sun.reflect.annotation.AnnotationParser#annotationForMap

庫本身很小,並沒有依賴關係。

披露:我是GeAnTyRef的開發者。

+1

我寧願這比其他方法,因爲它提供了最好的結果(等同於[貢納爾的答案](https://stackoverflow.com/a/16326389/294657)),因爲它不使用Oracle JDK內部類像Tobias'es的回答,這可能會使其與其他JDK/JVM不兼容。 – hoijui 2018-02-12 07:34:25