Javaでアノテーションを作ってみた。


はじめに

業務をしていて、アノテーションについて理解できていないことに気が付きました。
@Override, @Duplicate, @Test とか付与するのはわかるんですが、仕組みがわかっていないので調べてみました。

環境

  • OS Windows10
  • Java 11.0.1
  • Pleiades All in One Eclipse (2018-12)

Javaにおけるアノテーションとは

以下はwikipediaより。

Javaのアノテーションはクラスやメソッド、パッケージに対してメタデータとして付加情報を記入する機能で、Java SE 5 で追加された。 アノテーションはjava.lang.annotation.Annotationインタフェースを実装することで自作することもできる。

Javaにおけるアノテーションの種類

アノテーションの種類は、以下の3つに分類されます。

  • マーカー・アノテーション – データが無く名前だけを持つアノテーション。
    例:@Override, @Duplicate
  • 単一値アノテーション – データを一つだけ持つアノテーション。見かけはメソッド呼び出しに似ている。 例:@SuppressWarnings
  • フル・アノテーション – 複数のデータを持つアノテーション。

習うより慣れろで作ります

アノテーションクラスを作成します

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

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Info {
    String value();
}

アノテーションクラスを定義するには以下のアノテーションを付与します。

  • @Retention アノテーションの読み込みタイミングを指定できます。
    java.lang.annotation.RetentionPolicyから選択します。

CLASS : コンパイル時にクラスファイルに記録される。実行時にVMに読み込まれない。
RUNTIME : 実行時にVMに読み込まれる
SOURCE : コンパイル時に破棄

  • @Target 注釈型が適用可能なプログラム要素の種類を示します。
    java.lang.annotation.ElementType から選択します。

ANNOTATION_TYPE : アノテーションに適用可
CONSTRUCTOR : コンストラクタに適用可
FIELD : フィールドに適用可
LOCAL_VARIABLE : ローカルに適用可
METHOD : メソッドに適用可
PACKAGE : パッケージに適用可
PARAMETER : 引数に適用可

今回は、メソッド実行時にアノテーションの値を取得する処理を作成したいので、
@RetentionRUNTIME@TargetMETHOD に指定します。

アノテーション付与クラスと呼び出しクラスを作成します

呼び出すクラスになります。
作成したInfoアノテーションをメソッドに付与します。

AnnotationInstance.java
public class AnnotationInstance {
    @Info("hoge")
    public void execute() {
        System.out.println("Hello World!!");
    }
}

@Info("hoge")
@Infoアノテーションに値を設定しています。
valueにhogeが設定されます。

呼び出す側のメインクラスになります。

AnnotationMain.java
import java.lang.reflect.Method;

public class AnnotationMain {

    public static void main(String[] args) {
        try {
            Class<?> clazz = Class.forName("AnnotationInstance");
            Method method1 = clazz.getMethod("execute", new Class<?>[] {});
            Info info1 = method1.getAnnotation(Info.class);
            System.out.println(info1.value());
        } catch (ClassNotFoundException | NoSuchMethodException | SecurityException e) {
            e.printStackTrace();
        }
    }
}

リフレクションでメソッドを取得し、その先でアノテーションクラスを取得します。

実行してみます

上記で作成した AnnotationMain.java クラスを実行すると以下の結果が出力されます。

実行結果
hoge

AnnotationInstanceexecute()メソッドに指定された@Infoアノテーションの値が取得されていることが確認できました。

さいごに

使ってみると意外と簡単にできました。
この記事を書く過程で、アノテーションクラスの実装を改めていくつか見ることになりました。
普段あまり触れるものではないですが、フレームワークやパッケージ開発なので使われてるんでしょうね。
今まで読めていなかったので、今後は苦手意識を持たずに読んでいこうと思います。
リフレクションも久しぶりに触りました。そちらもあまり理解できていないので、またじっくり調べてみようと思います。

参考にしたサイト

アノテーション - Wikipedia
https://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%8E%E3%83%86%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3#Java%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E3%82%A2%E3%83%8E%E3%83%86%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3
ちょっと特殊なJavaのアノテーション - Qiita
https://qiita.com/kashira2339/items/6450714e42c37b441514
独自のアノテーションを作成して値を取得するサンプル | ITSakura
https://itsakura.com/java-annotation-make