アノテーションでソースコードが自動生成できるように なったのはJavaの言語仕様上革命的だと思うのだが いまいち認識されていない気がする。

多分、アノテーションプロセッサを実装するのが 非常に敷居が高いせいではないかと思う。

そこで、アノテーションクラスと Velocity のテンプレートだけ書くと簡単な注釈処理が作れる フレームワーク的な物を作ってみた。

フレームワークのブランク・プロジェクトのURLは以下。

  • https://kotemaru.googlecode.com/svn/tags/apt-helper-dir-bata/apt-helper-blank

プロセッサのソース

最小だと @ProcessorGenerate を定義したアノテーションクラスと 対応する Velocity のテンプレートを作成するだけ。

  • src/sample/annotation/SimpleAnno.java: package sample.annotation; import java.lang.annotation.*; import org.kotemaru.apthelper.annotation.ProcessorGenerate; @ProcessorGenerate( template="SimpleAnno.vm", // Velocityのテンプレートファイル名。 path=".", // 出力先パッケージへの相対パス。 suffix="Impl" // 出力クラス名に追加する文字列。 //helper=MyHelper.class // ユーザ定義のの補助クラス。 ) @Retention(RetentionPolicy.CLASS) @Target(ElementType.TYPE) public @interface SimpleAnno { String name() default "default"; String type() default "default"; String value() default "default"; }
@ProcessorGenerate は僕の作ったアノテーションで パラメータにしたがったアノテーション・プロセッサを自動生成する。
  • src/sample/annotation/SimpleAnno.vm: #* 定義済変数 ${packageName} : このクラスのパッケージ名 ${className} : このクラスのクラス名 ${masterClassDecl} : アノテーションの定義された元クラスの TypeDeclaration ${annotation} : 元クラスに定義されたアノテーション ${helper} : ユーザ定義の補助クラスインスタンス *# package ${packageName}; public class ${className} implements ${masterClassDecl} { public boolean ${annotation.name()}(${annotation.type()} arg) { return arg.equals(${annotation.value()}); } }
@ProcessorGenerateのtemplateで指定されたVelocityテンプレート。

${masterClassDecl}から元クラスのメソッドやフィールドの情報がたどれるが Mirror API の知識は必要。

  • http://java.sun.com/javase/ja/6/docs/ja/jdk/api/apt/mirror/index.html
${helper}は Velocity の機能だけでは足りなくなるので Java を呼べるようにしている。 この例では使っていない。

プロセッサの作成

これでプロジェクトをビルドすると @SimpleAnno が使える アノテーションプロセッサ apt-sample-1.0.jar が生成される。 (jarの名前は build-jar.xml に記述)

プロセッサを適用するプロジェクト

作成したプロセッサを使用する別のプロジェクトを用意する。
サンプルのURLは以下。

  • https://kotemaru.googlecode.com/svn/tags/apt-helper-dir-bata/apt-helper-use-test
このプロジェクトには作成した apt-sample-1.0.jar とブランクプロジェクトの lib/ の下の *.jar をコピーしてアノテーション・ファクトリに登録し、 apt-sample-1.0.jar をビルドパスに入れる。

プロセッサを適用してソースコードを生成

自前のアノテーション @SimpleAnno を使うソースを作成する。

  • src/test/master/SimpleAnnoTest.java: package test.master; import sample.annotation.*; @SimpleAnno(name="hogehoge", type="Integer", value="Integer.valueOf(10)") public class SimpleAnnoTest { // dummy. }
これをビルドすると .apt_generated/ に SimpleAnno.vm をテンプレートとする SimpleAnnoTestImpl.java が生成され コンパイルもされる。

  • .apt_generated/test/master/SimpleAnnoTestImpl.java: package test.master; public class SimpleAnnoTestImpl implements test.master.SimpleAnnoTest { public boolean hogehoge(Integer arg) { return arg.equals(Integer.valueOf(10)); } }
コンパイル時には SimpleAnnoTestImpl.java は存在するので 他のソースから SimpleAnnoTestImpl クラスを参照しても問題無い。
apt-helper-1.0.jar のソースは以下。
  • https://kotemaru.googlecode.com/svn/tags/apt-helper-dir-bata/apt-helper
もうちょっと複雑な例は AutoBean の方を見てください。

Mirror API を理解しないと使えない事には変わり無いのですが 標準の Visiter 方式に比べれば遥かに分かり易いですし ファクトリとプロセッサが自動生成されるだけでも ずいぶん敷居が下がると思います。

ドキュメント他、色々足りていませんが需要があれば頑張ります。 コメントに入れてください。



関連記事: Javaのアノテーションでsetter/getterを自動生成してみた