1つの要素に同じタイプの複数の注釈がありますか?


88

1つの要素(この場合はメソッド)で同じタイプの2つ以上の注釈を平手打ちしようとしています。これが私が作業しているおおよそのコードです:

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

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

上記をコンパイルすると、javacはアノテーションの重複について文句を言います。

max @ upsight:〜/ work / daybreak $ javac Dupe.java 
Dupe.java:5:アノテーションが重複しています

このような注釈を繰り返すことは単に不可能ですか?経験的に言えば、上記の@Fooの2つのインスタンスは、内容が異なるため違いませんか?

上記が不可能な場合、考えられる回避策は何ですか?

更新:ユースケースについて説明するように求められました。いきます

私は、MongoDBなどのドキュメントストアにPOJOを「マップ」するための、構文の糖度の高いメカニズムを構築しています。インデックスをゲッターまたはセッターの注釈として指定できるようにしたいのですが。これは不自然な例です:

public class Employee {
    private List<Project> projects;

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

明らかに、ProjectのさまざまなプロパティでEmployeeのインスタンスをすばやく検索できるようにしたいと考えています。@Indexを異なるexpr()値で2回指定するか、受け入れられた回答で指定されたアプローチを取ることができます。Hibernateはこれを実行し、ハックとは見なされませんが、少なくとも1つの要素で同じタイプの複数のアノテーションを使用できるようにすることは、依然として理にかなっていると思います。


1
Java 7でプログラムを許可するために、この重複ルールを緩和する取り組みがあります。使用例を説明していただけますか?
notnoop 2009年

質問を編集して、なぜこれをしたいのかを説明しました。ありがとう。
最大A.

複数の修飾子にBeanを提供できるようにすることは、CDIで便利です。たとえば、 "@ Produces @PackageName(" test1 ")@PackageName(" test2 ")"を修飾して、2か所でBeanを再利用しようとしたところ
Richard Corfield

さらに、CDIはコンポジットを1つの修飾子と見なすため、以下の答えはその問題を解決しません。
Richard Corfield

回答:


139

同じタイプの2つ以上の注釈は許可されていません。ただし、次のようなことができます。

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

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

ただし、コードではFoosアノテーションの専用処理が必要です。

ところで、私は同じ問題を回避するためにこれを2時間前に使用しました:)


2
これをGroovyでも実行できますか?
Excel20 2012年

5
@ Excel20はい。ただし、角括弧を使用する必要があります@Foos([@Foo(bar="one"), @Foo(bar="two")])groovy.codehaus.org/Annotations+with+Groovyを
sfussenegger

少し遅くなりますが、Foos内のFooのリストを処理できるアドバイスを指摘しますか?現在のところ、メソッドの結果を処理しようとしていますが、Foosはインターセプトされますが、Fooのアドバイスは入力されません
Stelios Koussouris


20

言及された他の方法とは別に、Java8にはもう1つ冗長な方法があります。

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

上記の両方が印刷されます:

@ com.FooContainer(value = [@ com.Foo(value = 1)、@ com.Foo(value = 2)、@ com.Foo(value = 3)])

@ com.FooContainer(value = [@ com.Foo(value = 1)、@ com.Foo(value = 2)、@ com.Foo(value = 3)])


FooContainerのメソッド/フィールド名は「value()」という厳密な名前にする必要があることを指摘する価値があります。そうしないと、Fooはコンパイルされません。
Tomasz Mularczyk 2016年

...また、注釈型(FooContainer)を含むことは、繰り返し可能な注釈型(Foo)よりも多くの型に適用できません。
Tomasz Mularczyk 2016年

16

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() {}

12

sfusseneggerが言ったように、これは不可能です。

通常の解決策は、前の注釈の配列を処理する「複数の」注釈を作成することです。通常は「s」サフィックスを付けて同じ名前にします。

ちなみに、これは大規模なパブリックプロジェクト(Hibernateなど)で非常に使用されているため、ハッキングと見なすべきではなく、このニーズに対する正しいソリューションと見なす必要があります。


必要に応じて、以前のアノテーションで複数の値を処理できるようにする方がよい場合があります

例:

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

これは不慣れなことだと知っていました。思い出をリフレッシュしてくれてありがとう。
最大A.

Java 8で可能になりました
Anis

4

他の回答を最も単純な形式に組み合わせる...注釈と単純な値のリスト...

@Foos({"one","two"})
private String awk;

//...

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

3

パラメータ「bar」が1つしかない場合は、「value」という名前を付けることができます。この場合、次のように使用するときにパラメーター名をまったく記述する必要はありません。

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

少し短くてきれいです。


正しい点ですが、これはOPの質問にどのように答えようとするのでしょうか。
モルデチャイ2017年

@MouseEventあなたは正しいです、それはsfusseneggerからのトップアンサーの改善のほうが多かったので、そこでのコメントにもっと属しています。しかし、繰り返し可能な注釈のために、答えはとにかく時代遅れです...
golwig

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.