アノテーションを読み込んでクラスやフィールドなどの情報を管理するという手法が可能になりますが、そのためにメタアノテーションを知る必要があります。 メタアノテーションとは、単純にアノテーションに指定するアノテーションです。
例えば、デフォルトでアノテーションは、クラスやフィールド、メソッドやコンストラクタなど、アノテーションが指定できるあらゆる宣言に記述可能です。 しかし、アノテーションの目的によってはクラスだけに指定して意味のあるものや、メソッドだけに指定して意味のあるものが存在します。 例として、メタアノテーションはアノテーションに指定するためのアノテーションであり、メタアノテーションをクラスに指定することに意味はありません。 こうした問題を解決するための、アノテーションの振る舞いや制限を指定するのがメタアノテーションなのです。
メタアノテーションには、コンパイラが認識することができる標準メタアノテーションと呼ばれるものが用意されています。 この標準メタアノテーションは java.lang.annotation パッケージで宣言されていて、アノテーションの扱いを決定する重要な存在です。
java.lang.annotation.Target アノテーションは、アノテーション型の宣言にのみ利用できるメタアノテーションであり、アノテーションの対象を指定することができます。 Target アノテーションは、シングル・メンバ・アノテーションなので、value() という名前のメソッドを持ちます。
public abstract ElementType[] value
このメンバは ElementType[] 型なので、Target アノテーションは ElementType の配列で初期化されなければなりません。 ElementType 型は java.lang.annotation.ElementType 列挙型で、アノテーションの対象要素を表す定数を提供しています。
定数 | 解説 |
---|---|
ANNOTATION_TYPE | アノテーション |
CONSTRUCTOR | コンストラクタ |
FIELD | フィールド |
LOCAL_VARIABLE | ローカル変数 |
METHOD | メソッド |
PACKAGE | パッケージ |
PARAMETER | パラメータ |
TYPE | クラス、インタフェース、または列挙型 |
アノテーションの対象がクラスなどの型なのであれば、アノテーション宣言で Target アノテーションに ElementType.TYPE を指定すればよいのです。 複数の要素を対象とするには、{ } で囲んで配列の定数として渡します。
import java.lang.annotation.*; @Target(ElementType.TYPE) @interface Copyright { String value(); } @Copyright("LeonAkasaka") //OK public class Test { @Copyright("LeonAkasaka") //エラー public static void main(String [] args) { } }
このプログラムの Copyright アノテーションは、クラス、インタフェース、または列挙型にのみ指定できる ElementType.TYPE を対象に指定しています。 そのため、Test クラスに Copyright を指定することは問題ありませんが、main() メソッドに指定した場合はコンパイルエラーとなります。
Target アノテーションも Target アノテーションで ElementType.ANNOTATION_TYPE を設定されています。 そのため、Target アノテーションはアノテーションにしか指定できません。
アノテーションは、他のツールからプログラムの注釈情報をプログラム的に読み込むことができる重要な機能ですが、プログラムの実行時に影響を及ぼすものではありません。 そのため、アノテーション情報を実行時にメモリに読み込むことが、必ずしも有益になるとは限らないのです。 実行時にクラスが保有する必要の無いアノテーションであれば、コンパイル時に破棄するか、クラスファイルを読み込む時にアノテーションは読み込まないようにするという方法が考えられます。
このように、アノテーションを実行時に VM に読み込ませるかどうかを指定するメタアノテーションが java.lang.annotation.Retention アノテーションです。 Retantion アノテーションはシングル・メンバ・アノテーションです。
public abstract RetentionPolicy value
java.lang.annotation.RetentionPolicy 列挙型は、アノテーションの配置方法を指定する定数が提供されています。
定数 | 解説 |
---|---|
CLASS | アノテーションはコンパイラによってクラスファイルに記録されます。しかし、実行時に VM に読み込まれることはありません。 |
RUNTIME | アノテーションはコンパイラによってクラスファイルに記録され、実行時に VM に読み込まれます。 |
SOURCE | アノテーションはコンパイル時によって破棄されます。 |
デフォルトで、アノテーションは CLASS が指定されています。 アノテーション情報はクラスファイルに記録されますが、実行時に読み込まれることはありません。 そのため、実行時にリフレクション API からアノテーションを取得することはできません。
SOURCE は、コンパイル時にアノテーション情報がソースから破棄されてしまいます。 このタイプのアノテーションは、コンパイラや総合開発環境のソース管理機能などに情報を通知するためのものです。
import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) @interface Copyright { String value(); } @Copyright("LeonAkasaka") public class Test { public static void main(String [] args) { } }
このプログラムの Copyright アノテーションは、RetentionPolicy.RUNTIME の Retention メタアノテーションを持ちます。 コンパイラは、Copyright アノテーションをクラスファイルに埋め込み、VM は実行時にアノテーションをメモリにロードするでしょう。 実行時に、リフレクション API を用いてアノテーション情報を得ることができます。