Javaのアノテーションについて
こんにちは、imamotoです。
私は入社4年目で、今まではほとんどPHPで開発する案件に参画していましたが、今年の1月から新たにJavaの案件に参画しています。
そちらの現場では週1回、開発メンバーでホスト持ち回りでJavaの勉強会を行っていて、先日私もJavaのアノテーションについてプレゼンを行いました。
Javaとガッツリ向き合うのはほぼ入社時の研修以来で、アノテーションについても細かいことはあまり知らず、基本的なことから改めて勉強する良い機会となりました。
せっかく資料も作ったのでその時発表した内容をこのブログにも書いてみようと思います。
プレゼン資料(改)
アノテーションとは
アノテーション とは「注釈」を意味し、クラスやメソッド、パッケージに対して付加情報を記入する機能です。
Java SE 5で追加され、以下のコードのように「@ + アノテーション名」という形式で使用します。
アノテーションの分類
アノテーションが持つデータの数による分類
- マーカー・アノテーション
- データが無く名前だけを持つ アノテーション
- 例) @Override, @Duplicate
- 単一値アノテーション
- データを一つだけ持つアノテーション
- 例) @SuppressWarnings
- フル・アノテーション
その他の分類
アノテーションの定義方法
以下のコードのようにアノテーションを定義することができます。
- " @interface アノテーション名 ”で定義
- メタアノテーション @Target でアノテーションを付与できる要素(メソッド、フィールド等)を限定
- java.lang.annotation.ElementTypeクラス(列挙型)の配列を値に指定する
- メタアノテーション @Retention でアノテーションの有効範囲を設定(コンパイル時のみ有効、実行時も有効等)を設定
- java.lang.annotation.RetentionPolicyクラス(列挙型)を値に指定する
- デフォルト値はRetentionPolicy.CLASS
- メソッド名をキー名とした値を持てる
- 値の型はプリミティブ型・String・Class・列挙型・アノテーションとそれらの1次元配列に限定される
- 各キーには default キーワードでデフォルト値を設定できる
アノテーションの使い方
アノテーションは以下のように使うことができます。
- 値の指定は" @アノテーション名(キー名=値) "という形で行う
- デフォルト値が指定されている場合、値の指定は省略できる
- 単一値アノテーションで値のキー名が value の場合のみ、キー名を省略できる
- メソッド呼び出しのような形になる
コンパイル時に処理を行うアノテーションを自作してみる
自作アノテーション概要
以下のようなアノテーションをプレゼン用に自作してみました。
- アノテーション名: ToDo
- message(), expiration()の2つのメソッドを持つ (フル・アノテーション)
- コンパイル時には常にmessageの値を警告表示
- expirationで指定された日付を過ぎている時はコンパイルエラー
コンパイル時に処理を行うアノテーションの作り方をざっくり紹介
- javax.annotation.processing.AbstractProcessorを継承したToDoProcessorクラス作成
- public boolean process(Set<? extends TypeElement> typeElements, RoundEnvironment roundEnv)を実装
- javac -processor Processorクラスの完全修飾名 コンパイル対象.java で、コンパイル時にprocessメソッドが実行される
コード紹介
- messageは必須
- expirationはStringで、日付を8桁で指定
- デフォルト値は "19700101"
ToDoProcessorクラス(コンパイル時の処理を記述)
- @SupportedSourceVersion でJavaのバージョン指定
- @SupportedAnnotationTypes でコンパイル時に処理を行うアノテーションを指定
- 全てのアノテーションで処理を行う場合は "*" を指定
- processメソッドを実装
Processorクラスの処理を行わせるためのコマンド
$ javac todo/ToDo.java $ javac todo/ToDoProcessor.java $ javac -processor todo.ToDoProcessor todo/ToDoTest.java
出力内容
$ javac -processor todo.ToDoProcessor todo/ToDoTest.java 警告: @ToDo at over5characters(java.lang.String) : if文が不要なので1行にまとめる todo/ToDoTest.java:6: エラー: ToDoの対応期限が切れています。対応期限2016-02-11 public static boolean over5characters(String target) { ^ エラー1個 警告1個
- -processor オプションを使ってコンパイルを行う
- 普通はProcessorクラスを含むjarを作成してクラスパスに追加する
- META-INF/services/javax.annotation.processing.Processor というファイルにProcessorクラス名を記載する
まとめ
今回のプレゼンを通して、普段深く考えずに当たり前のように使っているアノテーションについてちゃんと知る良い機会となりました。
また、定義方法やコンパイル時の処理追加方法は意外とシンプルで覚えやすいと感じました。
@ToDoアノテーションは我ながら恐ろしいコードを書いてしまったと感じていますが、放置されたTODOコメントに悩まされている方は是非使ってみてください!!!
最後にgithubのurlを貼っておきますので、コンパイルしてみたい方はcloneして試してみてください。
GitHub - ip-imamoto/annotation-study
それではまた!