読者です 読者をやめる 読者になる 読者になる

ほげほげ(仮)

仮死状態

アノテーションの利用(3)

Java

今回はコンパイル時にアノテーション処理を行おうと思う


今回はjavacのコマンドを使っていくので、eclipseは使わずテキストエディタでやる



まずはアノテーションアノテーションを使ったクラスを作る

Sampleアノテーション

@Sample("Test クラス")
public class Test {

    @Sample("bar フィールド")
    private Bar bar;

    @Sample("デフォルトコンストラクタ")
    public Test() {
        bar = new Bar();
    }

    @Sample("hoge メソッド")
    public void hoge() {
        bar.hoge();
    }

}


Testクラスで利用されているBarクラス

@Sample("Bar クラス")
public class Bar {

    @Sample("hoge メソッド")
    public void hoge() {
         System.out.println("HOGE");
    }

}

ここまでクラスを作成したらコンパイルはせずに置いといて次にアノテーションを処理するクラスを作る

アノテーションを処理するクラスはjavax.annotation.processing.Processorを継承し、

processメソッドをオーバーライドする


とりあえずは作ってみる

import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;

@SupportedSourceVersion(SourceVersion.RELEASE_6)
@SupportedAnnotationTypes("Sample")
public class SampleProcessor extends AbstractProcessor {

    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnvironment) {

        for (TypeElement annotation: annotations) {
            Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(annotation);
            for (Element element: elements) {
                Sample sample = element.getAnnotation(Sample.class);
                System.out.println("Sample at " + element);
                System.out.println("   Value: " + sample.value());
            }
        }
        return true;
    }

}


解説は後に回して、実際にコンパイルしていく


はじめにSampleアノテーションをコンパイル

javac Sample.java


次にアノテーションの処理を行うSampleProcessorをコンパイル

javac SampleProcessor.java


最後にTestクラスをコンパイルする

今回はアノテーションを処理するクラスを指定する-processorのオプションを使う

javac -processor SampleProcessor Test.java


たぶんコンパイルすると色々出力されたあとに下のような警告がでると思う

警告:暗黙的にコンパイルされたファイルは注釈処理に渡されません。
-implicit を使用し暗黙的コンパイルのポリシーを指定して下さい。


この警告はTestクラスが使用するBarクラスのアノテーションの処理をどうするかを明示的に示してないためにでる警告

これを解消するには-implicitを使う

  • implicit:classは暗黙的にロードするクラスのコンパイルとアノテーション処理を行い、


次のようなコマンドでコンパイルすれば警告は出力されなくなる

javac -processor SampleProcessor -implicit:class Test.java


コンパイルすると次のようなTestクラスに設定したアノテーション情報が出力されるはず

Sample at Test
   Value: Test クラス
Sample at bar
   Value: bar フィールド
Sample at Test()
   Value: デフォルトコンストラクタ
Sample at hoge()
   Value: hoge メソッド


ここまで出来たらアノテーション処理クラスについて解説

一応、もっかいソースを書いとく

import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;

@SupportedSourceVersion(SourceVersion.RELEASE_6)
@SupportedAnnotationTypes("Sample")
public class SampleProcessor extends AbstractProcessor {

    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnvironment) {

        for (TypeElement annotation: annotations) {
            Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(annotation);
            for (Element element: elements) {
                Sample sample = element.getAnnotation(Sample.class);
                System.out.println("Sample at " + element);
                System.out.println("   Value: " + sample.value());
            }
        }
        return true;
    }

}


2行目
 AbstractProcessorクラスを継承するが、このクラスを継承したクラスをアノテーションプロセッサと呼ぶ

10行目
 このアノテーションプロセッサがサポートするバージョンを指定する
 この場合はJava SE 6まで対応する

11行目
 これは処理するアノテーションを指定する
 今回はSampleというアノテーションを処理するように指定している
 すべてのアノテーションを処理する場合は「*」と記述する

14行目
 processをオーバーライドする
 引数のannotationsはアノテーションの情報が格納されている
 roundEnvironmentはアノテーション処理に関する情報の問い合わせを行う

16、17行目
 引数で渡されたアノテーション情報をループし、アノテーションを取り出している

18、19、20、21行目
 アノテーション個別情報を取得して、getAnnotationメソッドでSampleクラスを取得している
 その後、情報を出力している

24行目
 アノテーションプロセッサは複数処理することが可能で、
 trueを返すと、引数annotationsに格納されている処理されたことになり
 falseを返すと次のアノテーションプロセッサに処理を依頼することになる


今回は簡単にアノテーション処理をやってみたが、正直、オレもイマイチ理解してないことが多い

アノテーションだけで1冊の本ができるんじゃないかと思うくらい深いと個人的には思う


↓に参考にしたURLを載せておくので、詳しくはココを参考にしてほしい
 (もしかしたら、会員登録が必要かも)
アノテーションを処理する その1

アノテーションを処理する その2

ちなみに参考のURLは「その7」まであって、かなりディープな内容



想像よりも内容がディープすぎて、しんどくなってきた

アノテーションの概要はつかめた気がするから、一旦これで勉強は終わろうと思う

たぶんアノテーションの処理を書くようなことは早々ないと思うし、あっても、そのころには忘れてそうだからね・・・


なんか中途半端で申し訳ないです