Javaで自作アノテーションを作成し値を取得する方法

Javaで自作アノテーションを作成し、アノテーションの値を取得するサンプルプログラムを紹介します。

# 環境

+ jdk1.8.0_231

```
C:\>java -version
java version "1.8.0_231"
Java(TM) SE Runtime Environment (build 1.8.0_231-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.231-b11, mixed mode)

C:\>
```

# 1. 自作アノテーションを作成

自作アノテーションのサンプルです。ここではメンバに「name」と「value」を持たせています。

```java:MyAnnotation.java
package test01;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)     // (1) @Retantionでアノテーション情報をどの段階まで保持するかを制御
@Target({                               // (2) @Targetどのようなタイプの要素に対して、そのアノテーションを付加できるのかを制御
    ElementType.TYPE,
    ElementType.FIELD,
    ElementType.CONSTRUCTOR,
    ElementType.METHOD
})
public @interface MyAnnotation {        // (3) MyAnnotationを作成
    String name();
    int value() default 0;
}
```

(1) の`@Retention`でアノテーション情報をどの段階まで保持するかを指定します。

`@Retention`には主に以下を設定することができます。

|値|説明|
|:--|:---|
|RetentionPolicy.SOURCE|アノテーションはソースレベルでのみ保持され、コンパイラによって無視されます。|
|RetentionPolicy.CLASS|アノテーションはコンパイル時にコンパイラーによって保持されますが、Java仮想マシン（JVM）によって無視されます。|
|RetentionPolicy.RUNTIME|アノテーションはJVMによって保持されるため、ランタイム環境で使用できます。|

ここでは`RetentionPolicy.RUNTIME`を指定します。

(2) の`@Target`でアノテーションを適用可能な場所を指定します。

`@Target`には主に以下を設定することができます。

|値|説明|
|:--|:---|
|ElementType.TYPE|クラス、インターフェース、アノテーション、enum型に適用可能にします。|
|ElementType.FIELD|フィールドに適用可能にします。|
|ElementType.CONSTRUCTOR|コンストラクタに適用可能にします。|
|ElementType.METHOD|メソッドに適用可能にします。|

ここでは`@Target`に`ElementType.TYPE`、`ElementType.FIELD`、`ElementType.CONSTRUCTOR`、`ElementType.METHOD`を指定します。

(3) で`MyAnnotation`の名前でアノテーションを作成します。メンバに`name`と`value`を設定します。

# 2. クラスにアノテーションを付与

`Sample`クラスのクラス、フィールド、コンストラクタ、メソッドに自作の`MyAnnotation`を付与します。

```java:Sample.java
package test01;

@MyAnnotation(name="class", value=100)              // (1) クラスにMyAnnotationを付与
public class Sample {

    @MyAnnotation(name="field", value=200)          // (2) フィールドにMyAnnotationを付与
    private String name;

    @MyAnnotation(name="constructor", value=300)    // (3) コンストラクタにMyAnnotationを付与
    public Sample() {}

    @MyAnnotation(name="method", value=400)         // (4) メソッドにMyAnnotationを付与
    public void execute() {
        System.out.println("execute");
    }
}
```

(1) クラスに自作アノテーション（`MyAnnotation`）を付与します。
(2) フィールドに自作アノテーション（`MyAnnotation`）を付与します。
(3) コンストラクタに自作アノテーション（`MyAnnotation`）を付与します。
(4) メソッドに自作アノテーション（`MyAnnotation`）を付与します。

# 3. アノテーションを取得して参照

```Main.java
package test01;

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

public class Main {

    public static void main(String[] args)
            throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException, SecurityException {

        // (1) クラスについているアノテーション（MyAnnotation）を取得
        Class<?> clazz = Class.forName("test01.Sample");
        MyAnnotation annoClass = (MyAnnotation) clazz.getAnnotation(MyAnnotation.class);
        System.out.println("class annotation : name=" + annoClass.name() + ", value=" + annoClass.value());

        // (2) フィールドについているアノテーション（MyAnnotation）を取得
        Field field = clazz.getDeclaredField("name");
        MyAnnotation annoField = (MyAnnotation) field.getAnnotation(MyAnnotation.class);
        System.out.println("field annotation : name=" + annoField.name() + ", value=" + annoField.value());

        // (3) コンストラクタについているアノテーション（MyAnnotation）を取得
        Constructor<?> cons = clazz.getConstructor();
        MyAnnotation annoCons = (MyAnnotation) cons.getAnnotation(MyAnnotation.class);
        System.out.println("constructor annotation : name=" + annoCons.name() + ", value=" + annoCons.value());

        // (4) メソッドについているアノテーション（MyAnnotation）を取得
        Method method = clazz.getMethod("execute");
        MyAnnotation annoMethod = (MyAnnotation) method.getAnnotation(MyAnnotation.class);
        System.out.println("method annotation : name=" + annoMethod.name() + ", value=" + annoMethod.value());

    }
}
```

(1) `Sample`クラスに付いているアノテーション（`MyAnnotation`）の内容を取得し表示します。
(2) `Sample`クラスのフィールド`name`に付いているアノテーション（`MyAnnotation`）の内容を取得し表示します。
(3) `Sample`クラスのコンストラクタに付いているアノテーション（`MyAnnotation`）の内容を取得し表示します。
(4) `Sample`クラスの`execute`メソッドに付いているアノテーション（`MyAnnotation`）の内容を取得し表示します。

# 参考

[Lesson: Annotations (The Java&trade; Tutorials < Learning the Java Language)](https://docs.oracle.com/javase/tutorial/java/annotations/ "Lesson: Annotations (The Java&trade; Tutorials < Learning the Java Language)")

---

以上