web-dev-qa-db-ja.com

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つのインスタンスは、内容が異なるために異なりませんか?

上記が不可能な場合、潜在的な回避策は何ですか?

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

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

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のインスタンスをすばやく見つけることができるようにしたいのです。異なるexpr()値で@Indexを2回指定するか、受け入れられた回答で指定されたアプローチを取ることができます。 Hibernateはこれを実行し、ハックとは見なされませんが、少なくとも1つの要素に同じタイプの複数の注釈を許可することは理にかなっていると思います。

82
Max A.

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

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

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

ただし、コード内でFoosアノテーションを専用に処理する必要があります。

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

133
sfussenegger

Java 8(2014年3月にリリース)では、繰り返し/重複する注釈を記述することができます。 http://docs.Oracle.com/javase/tutorial/Java/ annotations/repeating.html

58
mernst

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

言及されている他の方法とは別に、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)])

13
Jatin

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

通常の解決策は、「複数の」注釈を作成するで、前の注釈の配列を処理します。通常、同じ名前に「s」という接尾辞が付けられます。

ちなみに、これは大規模な公共プロジェクト(Hibernateなど)で非常に使用されるため、ハックと見なされるべきではなく、このニーズに対する正しい解決策と見なされるべきです。


ニーズに応じて、以前の注釈で複数の値を処理できるようにするの方がよい場合があります。

例:

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

他の回答を最も単純な形式に結合します...値の単純なリストを持つ注釈...

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

//...

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

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

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

少し短くてきれいな、私見..

3
mihahh

Javaの現在のバージョンでは、次の注釈を使用してこの問題を解決できました。

@Foo({"one", "two"})