R-02: カスタムアノテーションの定義・処理
@interface でカスタムアノテーションを定義し、 リフレクションを使って実行時に処理する方法を学びます。 JUnit の @Test や Spring の @Autowired がどのように動いているかを理解できます。
カスタムアノテーションとは
アノテーション(Annotation)とは、コードに付加情報(メタデータ)を埋め込む仕組みです。@Override・@Deprecated などは Java 標準のアノテーションですが、@interface を使うと独自のアノテーションを定義できます。
アノテーション定義に必要なメタアノテーション
- @Retention: アノテーションをいつまで保持するかを指定します。 リフレクションで処理するには
RetentionPolicy.RUNTIMEが必須です。 - @Target: アノテーションをどこに付与できるかを制限します。
ElementType.METHOD(メソッド)・ElementType.FIELD(フィールド)・ElementType.TYPE(クラス・インターフェース)などを指定できます。
定義したアノテーションは、リフレクションのisAnnotationPresent() で存在確認、getAnnotation() で値の取得ができます。 この仕組みを使うと、JUnit のようなテストランナーやバリデーションフレームワークを自作できます。
サンプルコード
Java 8 からカスタムアノテーションを定義できます。@Retention(RetentionPolicy.RUNTIME) を付けることで実行時にリフレクションで取得できます。@Target でアノテーションを付与できる場所(メソッド・フィールド・クラスなど)を制限できます。
よくあるミス・注意点
⚠️ @Retention を省略するとリフレクションで取得できない
@Retention を省略した場合、デフォルトはRetentionPolicy.CLASS になります。 これは .class ファイルには残りますが、実行時(RUNTIME)には取得できません。 リフレクションで処理するアノテーションには必ず@Retention(RetentionPolicy.RUNTIME) を付けましょう。
⚠️ アノテーション要素にはデフォルト値を設定するか、使う側で必ず指定する
アノテーション要素に default を付けていない場合、 使う側でその要素を省略するとコンパイルエラーになります。 必須の情報は default なしで定義し、省略可能な情報は default 値を設定するのが一般的です。
⚠️ アノテーション要素の型は制限がある
アノテーション要素に使える型は、プリミティブ型・String・Class・Enum・アノテーション型・これらの配列に限定されています。List やObject などは使えないため、複数の値を渡したいときは配列を使います。
テストする観点
@TestCaseを付けたメソッドだけがrunTests()によって実行されること- アノテーションに設定した
descriptionとpriorityの値が正しく取得できること default値が指定されている要素を省略したとき、デフォルト値が使われること@NotNullを付けたフィールドに null を設定したとき、バリデーションエラーが出力されること@NotNullを付けたフィールドに null 以外の値を設定したとき、OK が出力されること(境界値)- アノテーションが付いていないフィールドがバリデーション対象にならないこと