2009-10-12 103 views
75

我正在嘗試在單個元素上敲擊兩個或多個相同類型的註釋,在這種情況下是一種方法。下面是我的工作的大概代碼:一個元素上有多個相同類型的註釋?

public class Dupe { 
    public @interface Foo { 
     String bar(); 
    } 

    @Foo(bar="one") 
    @Foo(bar="two") 
    public void haha() {} 
} 

當編譯以上,javac的抱怨重複註釋:

 
[email protected]:~/work/daybreak$ javac Dupe.java 
Dupe.java:5: duplicate annotation 

是它根本不可能再重複這樣的註解?從迂迴的角度來說,@Foo的兩個實例不是因爲內容不同而有所不同嗎?

如果以上是不可能的,什麼是一些潛在的解決方法?

更新:我已經被要求來形容我的使用情況。開始。

我建立一個語法sugarish機制,以「地圖」的POJO記錄商店,如MongoDB的。我想允許索引被指定爲getters或setter上的註釋。這裏是一個人爲的例子:

public class Employee { 
    private List<Project> projects; 

    @Index(expr = "project.client_id") 
    @Index(expr = "project.start_date") 
    public List<Project> getProjects() { return projects; } 
} 

很顯然,我希望能夠通過項目的各種屬性快速找到員工的情況。我可以用不同的expr()值指定@Index兩次,或者採用接受的答案中指定的方法。儘管Hibernate這樣做並不認爲是破解,但我認爲至少允許在單個元素上具有多個相同類型的註釋仍然有意義。

+1

有一個努力讓這個重複規則放鬆以允許你的程序在Java 7中運行。你能描述一下你的用例嗎? – notnoop 2009-10-12 12:07:23

+0

我已經編輯了我的問題,並說明了我爲什麼要這樣做。謝謝。 – 2009-10-12 13:46:08

+0

在CDI中它可能很方便,可以爲多個限定符提供一個bean。例如,我試圖通過限定它在兩個地方重用一個bean「@Produces @PackageName(」test1「)@PackageName(」test2「)」 – 2012-03-05 11:13:38

回答

127

相同類型的兩個或多個註釋是不允許的。不過,你可以這樣做:

public @interface Foos { 
    Foo[] value(); 
} 

@Foos({@Foo(bar="one"), @Foo(bar="two")}) 
public void haha() {} 

雖然你需要在代碼中專門處理Foos註解。

順便說一句,我只是用這2個小時前,以解決同樣的問題:)

+2

你也可以在Groovy中做到這一點嗎? – Excel20 2012-01-11 08:52:51

+5

@ Excel20是的。儘管如此,你仍然必須使用方括號。 '@Foos([@ Foo(bar =「one」),@Foo(bar =「two」)])'。請參閱http://groovy.codehaus.org/Annotations+with+Groovy – sfussenegger 2012-01-11 13:29:29

+0

今天晚了一點,但指出可以在Foos內處理Foo列表的建議嗎?目前,我正試圖編寫一個方法的結果,但儘管Foos被攔截,但Foo的建議永遠不會輸入 – 2013-09-05 05:30:01

12

至於說通過sfussenegger,這是不可能的。

通常的解決方案是建立一個「多重」註釋,它處理以前的註釋數組。它通常被命名爲相同,帶有's'後綴。

順便說一句,這是非常大的在公共項目(休眠例如)使用,所以它不應該被看作是一個黑客,而是對於這種需求的正確解決方案。


根據您的需求,它可以更好地讓你更早的註釋來處理多個值

例子:

public @interface Foo { 
     String[] bars(); 
    } 
+0

我知道這很怪異。謝謝你提醒我的記憶。 – 2009-10-12 13:38:27

+0

Java 8現在可以使用了。 – AnixPasBesoin 2017-02-26 12:41:09

3

如果只有1個參數 「酒吧」 你可以將其命名爲 「價值」。在這種情況下,你不會有在所有寫參數名稱,當你使用這樣的:

@Foos({@Foo("one"), @Foo("two")}) 
public void haha() {} 

有點短,更整潔,恕我直言..

+0

正確的觀點,但是這是如何回答OP的問題的? – Mordechai 2017-01-10 02:53:26

+0

@MouseEvent你是對的,我認爲這更像是sfussenegger的最佳答案的改進,因此在評論中屬於更多。但是,由於可重複的註釋,答案已經過時... – mihahh 2017-01-11 22:09:04

3

其他的答案組合成最簡單的形式...用值的簡單列表中的註釋...

11

http://docs.oracle.com/javase/tutorial/java/annotations/repeating.html

從Java8開始,你可以描述重複的註解:

@Repeatable(FooValues.class) 
public @interface Foo { 
    String bar(); 
} 

public @interface FooValues { 
    Foo[] value(); 
} 

注意,value是值列表的必填字段。

現在可以使用註釋重複他們,而不是填充所述數組:

@Foo(bar="one") 
@Foo(bar="two") 
public void haha() {} 
9
從提到的其他方式

除了,存在Java8多一個更加簡潔的方式:

@Target(ElementType.TYPE) 
@Repeatable(FooContainer.class) 
@Retention(RetentionPolicy.RUNTIME) 
@interface Foo { 
    String value(); 

} 

@Target(ElementType.TYPE) 
@Retention(RetentionPolicy.RUNTIME) 
@interface FooContainer { 
     Foo[] value(); 
     } 

@Foo("1") @Foo("2") @Foo("3") 
class Example{ 

} 

實施例通過默認獲取,FooContainer作爲註解

Arrays.stream(Example.class.getDeclaredAnnotations()).forEach(System.out::println); 
    System.out.println(Example.class.getAnnotation(FooContainer.class)); 

Both the上述打印:

@ com.FooContainer(值= [@ com.Foo(值= 1),@ com.Foo(值= 2),@ com.Foo(值= 3)])

@ com.FooContainer(值= [@ com.Foo(值= 1),@ com.Foo(值= 2),@ com.Foo(值= 3)])

+0

值得指出的是FooContainer中的方法/字段名稱必須嚴格命名爲「value()」。否則Foo將不會編譯。包含註釋類型(FooContainer)的 – Tomasz 2016-06-05 11:06:29

+0

...不能應用於比可重複註釋類型(Foo)更多的類型。 – Tomasz 2016-06-05 11:16:01

相關問題