読者です 読者をやめる 読者になる 読者になる

JavaのリフレクションAPIでアノテーション取得

JavaのリフレクションAPIアノテーションの取得を試してみたメモです。

前回の続きで、JavaのリフレクションAPIを利用して、アノテーションの取得を試してみました。

java.lang.reflect.AnnotatedElement

JavaのリフレクションAPIを利用することで、メタデータにアクセスできます。
java.lang.reflect.AnnotatedElementインターフェースを利用してアノテーションの取得を試したいと思います。

テスト用クラス

Mavenプロジェクトを作成し、pom.xmljunitとhamcrestだけdependencyに追加しました。

pom.xml

    <dependencies>
        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-all</artifactId>
            <version>1.3</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit-dep</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

テスト対象のクラスは下記のようなクラスを作りました。

package reflect;

import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

public class ReflectAnnotationExample {

    @FieldAnnotation
    public String name;

    @ConstructorAnnotaion
    public ReflectAnnotationExample(String name) {
        this.name = name;
    }

    @MethodAnnotation
    public String getName() {
        return name;
    }

    @Deprecated
    @ClassAnnotation
    public class DeprecatedClass {

    }

    @Target(FIELD)
    @Retention(RUNTIME)
    public @interface FieldAnnotation {

    }

    @Target(CONSTRUCTOR)
    @Retention(RUNTIME)
    public @interface ConstructorAnnotaion {

    }

    @Target(METHOD)
    @Retention(RUNTIME)
    public @interface MethodAnnotation {

    }

    @Target(TYPE)
    @Retention(RUNTIME)
    @Inherited
    public @interface ClassAnnotation {

    }
}

フィールド、コンストラクタ、メソッド、クラスのりテンションポリシーで
それぞれアノテーションを作成しました。
それぞれのアノテーションをフィールド、コンストラクタ、メソッド、クラスに付与しました。
DeprecatedClassには追加で、@Deprecatedも付与しました。

getAnnotation()

getAnnotation()では、引数で指定したアノテーションが存在する場合、指定した型のアノテーションが取得できます。
指定したアノテーションが存在しない場合nullが返ります。

    Annotation annotation = ReflectAnnotationExample.class.getAnnotation(ClassAnnotation.class);

getAnnotationメソッドは、AnnotatedElementインターフェースを実装しているクラスで使用できます。
Classクラス、Methodクラス、Fieldクラス、ConstructorクラスはAnnotationElementインターフェースを実装しています。

    // Classクラス
    Class clazz = ReflectAnnotationExample.DeprecatedClass.class;
    Annotation anno = clazz.getAnnotation(ClassAnnotation.class);

    // Methodクラス
    Method method = ReflectAnnotationExample.class.getMethod("getName");
    Annotation anno = method.getAnnotation(MethodAnnotation.class);

    // Fieldクラス
    Field field = ReflectAnnotationExample.class.getField("name");
    Annotation anno = field.getAnnotation(FieldAnnotation.class);

    // Constructorクラス
    Constructor cons = ReflectAnnotationExample.class.getConstructor(String.class);
    Annotation anno = cons.getAnnotation(ConstructorAnnotaion.class);

テストコード。

    public static class getAnnotationの確認 {
        @Test
        public void Classクラスからアノテーションが取得できること() throws Exception {
            Class clazz = ReflectAnnotationExample.DeprecatedClass.class;
            Annotation anno = clazz.getAnnotation(ClassAnnotation.class);
            assertThat(anno, is(instanceOf(ClassAnnotation.class)));
        }

        @Test
        public void Methodクラスからアノテーションが取得できること() throws Exception {
            Method method = ReflectAnnotationExample.class.getMethod("getName");
            Annotation anno = method.getAnnotation(MethodAnnotation.class);
            assertThat(anno, is(instanceOf(MethodAnnotation.class)));
        }

        @Test
        public void Fieldクラスからアノテーションが取得できること() throws Exception {
            Field field = ReflectAnnotationExample.class.getField("name");
            Annotation anno = field.getAnnotation(FieldAnnotation.class);
            assertThat(anno, is(instanceOf(FieldAnnotation.class)));
        }

        @Test
        public void Constructorクラスからアノテーションが取得できること() throws Exception {
            Constructor cons = ReflectAnnotationExample.class.getConstructor(String.class);
            Annotation anno = cons.getAnnotation(ConstructorAnnotaion.class);
            assertThat(anno, is(instanceOf(ConstructorAnnotaion.class)));
        }
    }
getAnnotations()

getAnnotations()では、要素に存在するすべてのアノテーションを取得できます。
要素にアノテーションが存在しない場合、長さ0の配列が返ります。

    Annotation[] annotation = ReflectAnnotationExample.class.getAnnotations;

getAnnotationsメソッドは、AnnotatedElementインターフェースを実装しているクラスで使用できます。
Classクラス、Methodクラス、Fieldクラス、ConstructorクラスはAnnotationElementインターフェースを実装しています。

テストコード。

    public static class getAnnotationsの確認 {
        @Test
        public void クラスのアノテーションが取得できること() throws Exception {
            Class clazz = ReflectAnnotationExample.DeprecatedClass.class;
            Annotation[] annos = clazz.getAnnotations();

            Annotation[] expected = {
                    clazz.getAnnotation(ClassAnnotation.class),
                    clazz.getAnnotation(Deprecated.class)
            };
            assertThat(annos, is(arrayContainingInAnyOrder(expected)));
        }

        @Test
        public void メソッドのアノテーションが取得できること() throws Exception {
            Method method = ReflectAnnotationExample.class.getMethod("getName");
            Annotation[] annos = method.getAnnotations();

            Annotation[] expected = {
                    method.getAnnotation(MethodAnnotation.class)
            };
            assertThat(annos, is(arrayContainingInAnyOrder(expected)));
        }
    }

テストコード

今回のテストコードの全体です。

ReflectAnnotationExampleTest.java

package reflect;

import org.junit.Test;
import org.junit.experimental.runners.Enclosed;
import org.junit.runner.RunWith;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.arrayContainingInAnyOrder;
import static org.junit.Assert.*;
import static reflect.ReflectAnnotationExample.*;

/**
 * Created by pppurple on 2016/07/26.
 */
@RunWith(Enclosed.class)
public class ReflectAnnotationExampleTest {
    public static class getAnnotationの確認 {
        @Test
        public void Classクラスからアノテーションが取得できること() throws Exception {
            Class clazz = ReflectAnnotationExample.DeprecatedClass.class;
            Annotation anno = clazz.getAnnotation(ClassAnnotation.class);
            assertThat(anno, is(instanceOf(ClassAnnotation.class)));
        }

        @Test
        public void Methodクラスからアノテーションが取得できること() throws Exception {
            Method method = ReflectAnnotationExample.class.getMethod("getName");
            Annotation anno = method.getAnnotation(MethodAnnotation.class);
            assertThat(anno, is(instanceOf(MethodAnnotation.class)));
        }

        @Test
        public void Fieldクラスからアノテーションが取得できること() throws Exception {
            Field field = ReflectAnnotationExample.class.getField("name");
            Annotation anno = field.getAnnotation(FieldAnnotation.class);
            assertThat(anno, is(instanceOf(FieldAnnotation.class)));
        }

        @Test
        public void Constructorクラスからアノテーションが取得できること() throws Exception {
            Constructor cons = ReflectAnnotationExample.class.getConstructor(String.class);
            Annotation anno = cons.getAnnotation(ConstructorAnnotaion.class);
            assertThat(anno, is(instanceOf(ConstructorAnnotaion.class)));
        }
    }

    public static class getAnnotationsの確認 {
        @Test
        public void クラスのアノテーションが取得できること() throws Exception {
            Class clazz = ReflectAnnotationExample.DeprecatedClass.class;
            Annotation[] annos = clazz.getAnnotations();

            Annotation[] expected = {
                    clazz.getAnnotation(ClassAnnotation.class),
                    clazz.getAnnotation(Deprecated.class)
            };
            assertThat(annos, is(arrayContainingInAnyOrder(expected)));
        }

        @Test
        public void メソッドのアノテーションが取得できること() throws Exception {
            Method method = ReflectAnnotationExample.class.getMethod("getName");
            Annotation[] annos = method.getAnnotations();

            Annotation[] expected = {
                    method.getAnnotation(MethodAnnotation.class)
            };
            assertThat(annos, is(arrayContainingInAnyOrder(expected)));
        }
    }
}

ソースはあげておきました。
github.com



終わり。