Eclipse で Pluggable Annotation Processing API

Pluggable Annotation Processing API はJava6から導入されたAPIです。これをつかうと、コンパイル時にアノテーションを読んでコードを生成したり、検証したりできます。javac実行時に処理できるのはドキュメント見るとわかるのですが、実はEclipseのビルド時にフックできます(Eclipseのエディタ上にエラー表示とかもできる)。Eclipseで動かそうとして情報をあさったんですが、なかなかわかりやすいものが見つからなかったのでここに書いておきます。実は簡単なんですけど、それがどこにも見当たらなかったんですよね。
Pluggable Annotation Processing APIの説明サイトはいくつかあって最後にリンクはっておきました。

EclipseはJava6で動かそう

まずは、EclipseがJava6でうごいていることを確認するといいです。
Eclipseのバージョンはここでは3.4.0を使っていますが新しければ新しいほどよさげです(メソッドのパラメータ名をとったりとかバグっているAPIがあるようです)。

新規プロジェクト(Processor提供側)を作ろう

processorという名前にしてみました。Java6を使わないといけません。

javax.annotation.processing.AbstractProcessorを継承したクラスをつくる。

Javaクラスを作ります。ここではSuppressWarningsで警告を消そうとしてもさらに警告を出すといういじわるなSuppressWarningsProcessorというクラスを作ります。ポイントはいくつかありますが、@SupportedAnnotationTypesで処理するアノテーションを指定してます。

import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
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;
import javax.tools.Diagnostic.Kind;

@SupportedSourceVersion(SourceVersion.RELEASE_6)
@SupportedAnnotationTypes("java.lang.SuppressWarnings")
public class SuppressWarningsProcessor extends AbstractProcessor {

    @Override
    public boolean process(Set<? extends TypeElement> annotations,
            RoundEnvironment roundEnv) {
        Messager messager = processingEnv.getMessager();
        for (TypeElement annotation : annotations) {
            for (Element element : roundEnv
                    .getElementsAnnotatedWith(annotation)) {
                messager.printMessage(Kind.WARNING, "@SuppressWarningsしちゃだめ",
                        element);
            }
        }
        return true;
    }
}
META-INF/services/javax.annotation.processing.Processor

META-INF/servicesの下のjavax.annotation.processing.Processorというファイルを作成し今作ったクラスを登録しておきます。クラス名を記述するだけ。改行で区切って複数書くこともできます。

SuppressWarningsProcessor
プロジェクトの構成

こんなかんじ。

processor
  +--src
      +--SuppressWarningsProcessor.java
      +--META-INF
          +--services
              +--javax.annotation.processing.Processor
jarの作成

Antを使うなりEclipseのExport機能でjarを作ります。
META-INF/services/javax.annotation.processing.Processorをちゃんと含めましょう。

新規プロジェクト(Processor利用側)を作ろう

ここではclientとします。Java6を使わないといけません。

Sample.java

適当にクラスを作りましょう。
以下はジェネリクスを使わないListをつかっちゃって@SuppressWarnings("unchecked")で警告を抑制しているというコードです。

import java.util.ArrayList;
import java.util.List;

@SuppressWarnings("unchecked")
public class Sample {

    void hoge() {
        List list = new ArrayList();
        System.out.println(list.size());
    }
}
Factory Pathの指定

プロジェクトを右クリックして「Java Compiler」-「Annotation Processing」-「Factory Path」とたどり、さっき作成したjarを登録します。
「Annotation Processing」と「Factory Path」の画面では両方とも「Enable project specific settings」にチェックをします。
OKとします。

エディタでSample.javaを確認

SuppressWarningsProcessorで処理されたワーニングメッセージが出ています。


ちなみにjavacするとこんな感じ

D:\workspaces\main\client\src>javac -cp D:\processor.jar Sample.java
Sample.java:5: 警告:@SuppressWarningsしちゃだめ
public class Sample {
       ^

まとめ

Eclipseプラグインよりできることは少ないですが、標準のAPIでできるのはいいですよね。javacで使えるし。他のIDEでのサポート状況はどうなんでしょうか?

Pluggable Annotation Processing APIの説明はTECHSCOREとJava SE 6完全攻略がわかりやすいです。

いろいろやろうとするとVisitorがいっぱい登場して楽しいです、javax.lang.model.utilパッケージとか。Visitor厨は必見です。

追記
リンク張った先のJavaDocは英語ですが、ダウンロードできるものは日本化されてます。

さらに追記 - 2010/12/12

このエントリを書いた時点ではまだありませんでしたが、今ならAptina Unitというとても便利なツールがあります。Pluggable Annotation Processing APIを使って何かを作ろうと思うなら、Aptina Unitを使うのはとてもおすすめです。テストやデバッグに使えることはもちろん、学習用にちょっと書いて動かしてみるといった場合にも重宝します。上に書いたようなjarにまとめたりする手順が一切不要です。

Pluggable Annotation Processing APIの具体的な使い方を知りたいというのであれば、AptinaDomaのコードを読んでみるのもおすすめです。