1. 概要

このチュートリアルでは、フィールドの注釈を取得する方法を学習します。 さらに、保持メタアノテーションがどのように機能するかについても説明します。 その後、フィールドのアノテーションを返す2つのメソッドの違いを示します。

2. アノテーションの保持ポリシー

まず、保持アノテーションを見てみましょう。 注釈のライフサイクルを定義します。 このメタアノテーションには、 RetentionPolicy 属性 。 つまり、 属性は、注釈が表示されるライフサイクルを定義します。

  • RetentionPolicy.SOURCE –ソースコードでのみ表示
  • RetentionPolicy.CLASS –コンパイル時にコンパイラーに表示されます
  • RetentionPolicy.RUNTIME –コンパイラとランタイムに表示されます

したがって、 RUNTIME保持ポリシーのみが、プログラムで注釈を読み取ることができます

3. リフレクションを使用してフィールドの注釈を取得する

それでは、注釈付きフィールドを持つサンプルクラスを作成しましょう。 3つの注釈を定義します。実行時に表示されるのは2つだけです。

最初の注釈は実行時に表示されます。

@Retention(RetentionPolicy.RUNTIME)
public @interface FirstAnnotation {
}

2番目のものは同じ保持を持っています:

@Retention(RetentionPolicy.RUNTIME)
public @interface SecondAnnotation {
}

最後に、ソースコードでのみ表示される3番目の注釈を作成しましょう。

@Retention(RetentionPolicy.SOURCE)
public @interface ThirdAnnotation {
}

次に、3つのアノテーションすべてでアノテーションが付けられたフィールドclassMemberを使用してクラスを定義しましょう。

public class ClassWithAnnotations {

    @FirstAnnotation
    @SecondAnnotation
    @ThirdAnnotation
    private String classMember;
}

その後、実行時に表示されているすべての注釈を取得しましょう。 フィールドの属性を検査できるJavaリフレクションを使用します:

@Test
public void whenCallingGetDeclaredAnnotations_thenOnlyRuntimeAnnotationsAreAvailable() throws NoSuchFieldException {
    Field classMemberField = ClassWithAnnotations.class.getDeclaredField("classMember");
    Annotation[] annotations = classMemberField.getDeclaredAnnotations();
    assertThat(annotations).hasSize(2);
}

その結果、実行時に使用可能な2つのアノテーションのみを取得しました。 メソッドgetDeclaredAnnotationsは、フィールドに注釈が存在しない場合、長さゼロの配列を返します。

スーパークラスフィールドのアノテーションも同じ方法で読み取ることができます。スーパークラスのフィールドを取得し、同じgetDeclaredAnnotationsメソッドを呼び出します。

4. フィールドに特定のタイプの注釈が付けられているかどうかを確認します

次に、特定の注釈がフィールドに存在するかどうかを確認する方法を見てみましょう。 フィールドクラスには、指定されたタイプの注釈が要素に存在する場合にtrueを返すメソッドisAnnotationPresentがあります。 classMemberフィールドでテストしてみましょう。

@Test
public void whenCallingIsAnnotationPresent_thenOnlyRuntimeAnnotationsAreAvailable() throws NoSuchFieldException {
    Field classMemberField = ClassWithAnnotations.class.getDeclaredField("classMember");
    assertThat(classMemberField.isAnnotationPresent(FirstAnnotation.class)).isTrue();
    assertThat(classMemberField.isAnnotationPresent(SecondAnnotation.class)).isTrue();
    assertThat(classMemberField.isAnnotationPresent(ThirdAnnotation.class)).isFalse();
}

予想どおり、 ThirdAnnotation は、 Retention meta-annotationSOURCE保持ポリシーが指定されているため、存在しません。

5. フィールドメソッドgetAnnotationsおよびgetDeclaredAnnnotations

次に、フィールドクラスによって公開される2つのメソッド、getAnnotationsgetDeclaredAnnotationsを見てみましょう。 Javadocによると、 getDeclaredAnnotations メソッドは、要素に直接存在するアノテーションを返します。 一方、Javadocは、 getAnnotations に対して、要素に存在するすべての注釈を返すと述べています。

クラスのフィールドには、その定義のすぐ上に注釈が含まれています。 その結果、関連する注釈の継承はまったくありません。 すべての注釈は、フィールド定義と一緒に定義する必要があります。 そのため、メソッドgetAnnotationsgetDeclaredAnnotationsは常に同じ結果を返します。

簡単なテストでそれを示しましょう:

@Test
public void whenCallingGetDeclaredAnnotationsOrGetAnnotations_thenSameAnnotationsAreReturned() throws NoSuchFieldException {
    Field classMemberField = ClassWithAnnotations.class.getDeclaredField("classMember");
    Annotation[] declaredAnnotations = classMemberField.getDeclaredAnnotations();
    Annotation[] annotations = classMemberField.getAnnotations();
    assertThat(declaredAnnotations).containsExactly(annotations);
}

さらに、フィールドクラスでは、getAnnotationsメソッドがgetDeclaredAnnotationsメソッドを呼び出すことがわかります。

@Override
public Annotation[] getAnnotations() {
    return getDeclaredAnnotations();
}

6. 結論

この短い記事では、アノテーションを取得する際の保持ポリシーのメタアノテーションの役割について説明しました。 次に、フィールドの注釈を読み取る方法を示しました。 最後に、フィールドのアノテーションが継承されていないことを証明しました。

いつものように、例のソースコードはGitHubから入手できます。