注釈処理ツール (apt) 入門

次の項目について説明します。

apt ツールは非推奨になりました

パッケージ apt に含まれる apt ツールおよびその関連 API は、JDK 7 以降で推奨されなくなり、JDK の次回メジャーリリースで削除される予定となっています。javac ツールで利用可能なオプションと、パッケージ javax.annotation.processing および javax.lang.model に含まれる API を使用して、注釈を処理してください。

apt API の代替のサマリー

次の表では、apt API の代替について概要を示します。

パッケージ com.sun.mirror.apt
apt の型 標準の代替
AnnotationProcessor javax.annotation.processing.Processor
AnnotationProcessorEnvironment javax.annotation.processing.ProcessingEnvironment
AnnotationProcessorFactory javax.annotation.processing.Processor
AnnotationProcessorListener アナログなし。
AnnotationProcessors アナログなし。
Filer javax.annotation.processing.Filer
Filer.Location javax.tools.StandardLocation
Messager javax.annotation.processing.Messager
RoundCompleteEvent アナログなし。
RoundCompleteListener アナログなし。
RoundState javax.annotation.processing.RoundEnvironment
パッケージ com.sun.mirror.declaration
apt の型 標準の代替
AnnotationMirror javax.lang.model.element.AnnotationMirror
AnnotationTypeDeclaration javax.lang.model.element.TypeElement
AnnotationTypeElementDeclaration javax.lang.model.element.ExecutableElement
AnnotationValue javax.lang.model.element.AnnotationValue
ClassDeclaration javax.lang.model.element.TypeElement
ConstructorDeclaration javax.lang.model.element.ExecutableElement
Declaration javax.lang.model.element.Element
EnumConstantDeclaration javax.lang.model.element.VariableElement
EnumDeclaration javax.lang.model.element.TypeElement
ExecutableDeclaration javax.lang.model.element.ExecutableElement
FieldDeclaration javax.lang.model.element.VariableElement
InterfaceDeclaration javax.lang.model.element.TypeElement
MemberDeclaration javax.lang.model.element.Element
MethodDeclaration javax.lang.model.element.ExecutableElement
Modifier javax.lang.model.element.Modifier
PackageDeclaration javax.lang.model.element.PackageElement
ParameterDeclaration javax.lang.model.element.VariableElement
TypeDeclaration javax.lang.model.element.TypeElement
TypeParameterDeclaration javax.lang.model.element.TypeParameterElement
パッケージ com.sun.mirror.type
apt の型 標準の代替
AnnotationType javax.lang.model.type.DeclaredType
ArrayType javax.lang.model.type.ArrayType
ClassType javax.lang.model.type.DeclaredType
DeclaredType javax.lang.model.type.DeclaredType
EnumType javax.lang.model.type.DeclaredType
InterfaceType javax.lang.model.type.DeclaredType
MirroredTypeException javax.lang.model.type.MirroredTypeException
MirroredTypesException javax.lang.model.type.MirroredTypesException
PrimitiveType javax.lang.model.type.PrimitiveType
PrimitiveType.Kind javax.lang.model.type.TypeKind
ReferenceType javax.lang.model.type.ReferenceType
TypeMirror javax.lang.model.type.TypeMirror
TypeVariable javax.lang.model.type.TypeVariable
VoidType javax.lang.model.type.NoType
WildcardType javax.lang.model.type.WildcardType
パッケージ com.sun.mirror.util
apt の型 標準の代替
DeclarationFilter javax.lang.model.util.ElementFilter
DeclarationScanner javax.lang.model.util.ElementScanner6
DeclarationVisitor javax.lang.model.element.ElementVisitor
DeclarationVisitors 代替はありません。
Declarations javax.lang.model.util.Elements
SimpleDeclarationVisitor javax.lang.model.util.SimpleElementVisitor6
SimpleTypeVisitor javax.lang.model.util.SimpleTypeVisitor6
SourceOrderDeclScanner javax.lang.model.util.SimpleElementVisitor6
SourcePosition 代替はありません。
TypeVisitor javax.lang.model.element.TypeVisitor
Types javax.lang.model.util.Types

apt とは

apt はコマンド行ユーティリティーで、注釈処理ツールです。検証が行われている指定されたソースファイルセットに存在する注釈に基づいて、注釈プロセッサを検出し実行します。この注釈処理ツールは、リフレクション API とサポートインフラストラクチャーのセットを使用して、プログラム注釈の処理を実行します (JSR 175)。apt リフレクト API は、構築時のソースベースで、プログラム構造に関する読み取り専用ビューを提供します。これらは、ジェネリクス (JSR 14) の追加後に、JavaTM プログラム言語の型システムを明確にモデルするために設計されました。最初に apt は、新しいソースコードとほかのファイルを作成できる注釈プロセッサを実行します。次に apt は、元のファイルと生成されたソースファイルのコンパイルを行うので、開発サイクルを簡素化できます。

なぜ apt を使用するべきか

注釈の使用が必要となるのは、新しい派生ファイル (ソースファイル、クラスファイル、配備記述子など) の生成に使用される情報を保持するベースファイルに注釈があり、ベースファイルとその注釈に論理的に一貫性がある場合です。つまり、ファイルセット全体の一貫性を手動で維持するのではなく、派生ファイルはベースファイルから生成されるので、ベースファイルだけを維持すれば良いということです。apt ツールは派生ファイルを作成することを目的として設計されました。

注釈に基づいて派生ファイルを生成する場合、ドックレットと比較すると apt には次の利点があります

注釈処理の目的以外に、apt はほかのリフレクションプログラミングタスクにも使用できます。

apt の使用方法

概要

まず apt は、操作されているソースコードにどんな注釈があるかを確認します。次に apt は、記述した注釈プロセッサファクトリを検索します。ファクトリで処理されている注釈が確認されます。次に apt は、操作されているソースファイルに存在する注釈をファクトリが処理する場合、注釈プロセッサを渡すようにファクトリに求めます。次に、注釈プロセッサが実行されます。プロセッサが新しいソースファイルを生成した場合、apt は新しいソースファイルが生成されなくなるまで、この処理を繰り返します。

注釈プロセッサの開発

注釈プロセッサの書き込みは、次の 4 つのパッケージに依存します。 各プロセッサは、com.sun.mirror.apt パッケージの AnnotationProcessor インタフェースを実装します。このインタフェースには、プロセッサを呼び出すために apt ツールにより使用される、1 つのメソッド process があります。プロセッサは 1 つまたは複数の注釈型を「処理」します。

プロセッサのインスタンスが、対応するファクトリ AnnotationProcessorFactory により返されます。apt ツールはファクトリの getProcessorFor メソッドを呼び出しプロセッサを保持します。この呼び出しの間に、ツールは AnnotationProcessorEnvironment を提供します。この環境でプロセッサは、開始するために必要なあらゆるもの (操作しているプログラム構造への参照や、新しいファイルを作成して警告とエラーメッセージを渡すことにより apt ツールと通信および連携する方法など) を検出します。

ファクトリを見つけるには 2 つの方法があります。使用するファクトリは「-factory」コマンド行オプションを使用して指定できます。または apt discovery プロシージャー中にファクトリを見つけることもできます。「-factory」オプションを使用すると、既知の単一ファクトリをもっとも簡単に実行できます。このオプションは実行される方法をファクトリがより詳細に制御する必要がある場合にも使用されます。特定のパスでファクトリを検出するために、検出プロシージャーは次に示す方法で jar ファイルから META-INF/services 情報を取得します。

-factory」オプションを使用して注釈プロセッサを作成して使用するには:

  1. 対象の注釈型の AnnotationProcessor を作成できる、AnnotationProcessorFactory を記述します。
  2. クラスパスに tools.jar を指定した状態で javac を使用してプロセッサおよびファクトリをコンパイルします。tools.jar には com.sun.mirror.* インタフェースが含まれます。
  3. コンパイルされたクラスファイル、またはコクラスファイルを含む jar ファイルを、apt を呼び出すときの適切なパスに置きます。
デフォルトの検出プロシージャーで注釈プロセッサを作成して使用する場合は、最初の 2 つの手順を使用してから、
  1. META-INF/services に、com.sun.mirror.apt.AnnotationProcessorFactory という名前の UTF-8 エンコードテキストファイル (内容は具象ファクトリクラスの完全修飾名のリスト、1 行に 1 個) を作成します。 (sun.misc.Service により使用されるものと同じ形式です)。
  2. ファクトリ、プロセッサ、および META-INF/services 情報を jar ファイルにパッケージ化します。
  3. jar ファイルを apt を呼び出すときの適切な場所に置きます。適切なパスについては、「検出」セクションで説明します。

注釈プロセッサの簡単な例

import com.sun.mirror.apt.*;
import com.sun.mirror.declaration.*;
import com.sun.mirror.type.*;
import com.sun.mirror.util.*;

import java.util.Collection;
import java.util.Set;
import java.util.Arrays;

import static java.util.Collections.*;
import static com.sun.mirror.util.DeclarationVisitors.*;

/*
 * This class is used to run an annotation processor that lists class
 * names.  The functionality of the processor is analogous to the
 * ListClass doclet in the Doclet Overview.
 */
public class ListClassApf implements AnnotationProcessorFactory {
    // Process any set of annotations
    private static final Collection<String> supportedAnnotations
        = unmodifiableCollection(Arrays.asList("*"));

    // No supported options
    private static final Collection<String> supportedOptions = emptySet();

    public Collection<String> supportedAnnotationTypes() {
        return supportedAnnotations;
    }

    public Collection<String> supportedOptions() {
        return supportedOptions;
    }

    public AnnotationProcessor getProcessorFor(
            Set<AnnotationTypeDeclaration> atds,
            AnnotationProcessorEnvironment env) {
        return new ListClassAp(env);
    }

    private static class ListClassAp implements AnnotationProcessor {
        private final AnnotationProcessorEnvironment env;
        ListClassAp(AnnotationProcessorEnvironment env) {
            this.env = env;
        }

        public void process() {
            for (TypeDeclaration typeDecl : env.getSpecifiedTypeDeclarations())
                typeDecl.accept(getDeclarationScanner(new ListClassVisitor(),
                                                      NO_OP));
        }

        private static class ListClassVisitor extends SimpleDeclarationVisitor {
            public void visitClassDeclaration(ClassDeclaration d) {
                System.out.println(d.getQualifiedName());
            }
        }
    }
}

このプロセッサの例では、いくつかの新しい言語とライブラリ機能が使用されています。まず、さまざまなユーティリティーメソッドの簡易名を使用できるように、static import が使用されます。たとえば、
unmodifiableCollection」を
Collections.unmodifiableCollection
の代わりに使用できます。
次に、ジェネリックコレクションが全体で使用されています。Arrays.asList メソッドが可変長引数メソッドになったので、コンマ区切りの文字列リストを受け取って目的の要素のリストを作成できます。Collections.emptySet メソッドはジェネリックメソッドで、型保証された空のセットを作成するために使用できます。process メソッド内の for ループは、コレクションをイテレートする拡張 for ループです。

注釈をプロセスに指定する

どの注釈を処理しているかツールに伝えるために、例に示されるように、ファクトリは import スタイル文字列のコレクションを返します。特定の文字列エントリの形式は次の 3 つのいずれかです。
*
すべての注釈を処理する。これは空の注釈リストも処理する。つまり、* を処理するファクトリは、重要なプロセッサを提供することを要求される可能性がある (注釈が存在しない場合でも)。この機能により com.sun.mirror API を使用して、一般的なソースコード処理ツールを記述できる。
foo.bar.Baz
正規名が「foo.bar.Baz」である注釈を処理する。
foo.bar.*
正規名が「foo.bar.」で始まる注釈を処理する。

apt ツールは、処理するファクトリの注釈セットをファクトリに提示します。注釈セットと注釈プロセッサ環境に基づいて、ファクトリは単一注釈プロセッサを返します。ファクトリが複数の注釈プロセッサを返したい場合はどうなりますか。ファクトリは com.sun.mirror.apt.AnnotationProcessors.getCompositeAnnotationProcessor を使用して、複数の注釈プロセッサを組み合わせてオペレーションを順番に行うことができます。

認識するコマンド行オプションを指定する

supportedOptions メソッドにより、ファクトリはどのコマンド行オプションを認識するかを apt とやり取りできます。「-A」で始まるコマンド行オプションは、注釈プロセッサとやり取りするために予約されています。たとえば、このファクトリが -Adebug-Aloglevel=3 などのオプションを認識すると、文字列「-Adebug」と「-Aloglevel」を返します。将来、どのファクトリも認識しない -A オプションが渡された場合は、apt はそのことを示すことができます。

apt コマンド行

独自のオプションに加えて、apt ツールは javac が受け入れるすべてのコマンド行オプションを受け入れます。javac オプションは (渡された場合)、最後の javac 呼び出しに渡されます。

apt 固有のオプションを次に示します。

-s dir
プロセッサ生成ソースファイルが配置されるディレクトリルートを指定します。ファイルはパッケージ名前空間に基づいてサブディレクトリに配置されます
-nocompile
ソースファイルをクラスファイルにコンパイルしません。
-print
指定したタイプのテキスト表現を出力します。注釈処理またはコンパイルは行いません。
-A[key[=val]]
注釈プロセッサへ渡すオプションです。このオプションは、apt が直接解釈するのではなく、それぞれのプロセッサで使用できるようになります。
-factorypath path
注釈プロセッサファクトリを検索する場所を指定します。このオプションを使用する場合、クラスパスのファクトリは検索されません。
-factory classname
使用する AnnotationProcessorFactory の名前。デフォルト検出プロセスをバイパスします。
apt がどのように javac オプションのいくつかを共有するかを次に示します。
-d dir
プロセッサと javac 生成のクラスファイルを置く場所を指定します。
-cp path または -classpath path
ユーザークラスファイルと注釈プロセッサファクトリを検索する場所を指定します。-factorypath が指定されている場合、クラスパスのファクトリは検索されません。
デバッグに役立つ、いくつかの apt 隠しオプションを次に示します。
-XListAnnotationTypes
検出された注釈型をリストします
-XListDeclarations
指定およびインクルードされた宣言をリストします
-XPrintAptRounds
初期および再帰的 apt ラウンドに関する情報を出力する
-XPrintFactoryInfo
ファクトリが処理を要求されている注釈に関する情報を出力します

apt ツールの動作

検出

コマンド行でソースファイルをスキャンしてどの注釈が存在しているかを確認したあとに、デフォルトでは apt ツールは適切なパスで注釈プロセッサファクトリを探します。-factorypath オプションが使用された場合、そのパスがファクトリを検索するための適切なパスになります。そうでない場合は、クラスパスが適切なパスです。どの注釈が処理されるかを確認するためにファクトリが照会されます。存在する注釈の 1 つをファクトリが処理する場合、その注釈が要求されているとみなされます。すべての注釈が要求されている場合は、ツールはその他のファクトリを探しません。注釈がすべて要求されたあと、またはそれ以上ファクトリが見つからない場合、apt はファクトリの getProcessorFor メソッドを呼び出し、そのファクトリが要求した注釈セットを渡します。各ファクトリは、該当する注釈セットに適した処理を実行するための単一プロセッサを返します。すべてのプロセッサが返されたあと、apt は順番に各プロセッサを呼び出します。プロセッサが新しいソースファイルを生成した場合、apt の再帰的ラウンドが発生します。再帰的 apt ラウンドでは、検出は前のラウンドでプロセッサを提供したファクトリで getProcessorFor を呼び出します (そのファクトリが現在の注釈のいずれも処理しない場合でも)。これにより、ファクトリは後続の apt ラウンドでリスナーを登録できます。ただし、ほとんどのファクトリはここで単純に AnnotationProcessors.NO_OP を返します。新しいソースファイルが生成されないラウンドのあとに、apt は元のおよび生成されたソースファイルで javac を呼び出します。プロセッサが検出されない、または検出されたプロセッサが存在する注釈を処理しない場合、apt を呼び出すことは、ソースファイルで直接 javac を呼び出すことと本質的に同じです。

ファクトリクラスが注釈処理の複数のラウンドで使用される場合、ファクトリクラスは 1 回ロードされ、ファクトリの getProcessorFor メソッドがラウンドごとに 1 回呼び出されます。これによりファクトリは、ラウンドをまたがって静的状態を保存できます。

-factory オプションが使用されている場合、指定されたファクトリだけが照会されます。

apt 処理のラウンド

apt の最初のラウンドは、入力ソースファイルを分析し、検出プロシージャーを実行し、結果の注釈プロセッサを呼び出します。apt の 2 番目のラウンドは、最初のラウンドで生成された新しいソースファイル (ある場合) を分析し、それらの新しいファイルで検出プロシージャーを実行し、結果の注釈プロセッサを呼び出します。同様に、2 番目のラウンドが新しいソースファイルを生成した場合、3 番目のラウンドは新しいソースを分析し、検出プロシージャーを実行する、のようになります。apt ラウンドは新しいソースファイルが生成されなくなるまで続きます。最後に、最後のラウンドのあとに、apt ツールはデフォルトで元のおよび生成されたソースファイルで javac を実行します。

リスナー

注釈プロセッサまたはファクトリは、その環境で addListener メソッドを使用してラウンドの終了時のためのリスナーを登録できます。ツールは、そのラウンドのすべての注釈プロセッサの実行が完了したあとに、登録されたリスナーを呼び出します。リスナーにはラウンドのステータスについての情報が渡されます (新しいソースファイルが書き出されたか、エラーが発生したか、完了したばかりのラウンドが最後のラウンドか、など)。リスナーは、すべての注釈処理が完了したときに、ファイルの末尾を書き出すために使用できます。同じクラスが AnnotationProcessor および RoundCompleteListener インタフェースの両方を実装できるので、同じオブジェクトを両方のコンテキストで使用できます。

リターンコード

最後の apt ラウンドのあとに javac が呼び出された場合、apt のリターンコードは、それらのファイルをコンパイルする javac のリターンコードになります。javac が呼び出されない場合、ツール自体またはプロセッサによりエラーが報告されなかったときは、apt の終了ステータスは 0 になります。形式が正しくないまたは不完全なソースファイルで apt を操作しても、それ自体では終了ステータスは 0 以外になりません。

宣言と型

ミラー API は、主に com.sun.mirror.declaration パッケージ内の Declaration インタフェースおよびそのサブインタフェースの階層によってソースコード構造体を表します。Declaration は、パッケージ、クラス、メソッドなどのプログラム要素を表し、通常はソースコードの特定部分に 1 対 1 で対応しています。Declarations は注釈可能な構造です。

型は、com.sun.mirror.type パッケージ内の TypeMirror インタフェースおよびそのサブインタフェースの階層により表現されます。型にはプリミティブ型、クラスおよびインタフェース型、配列型、型変数、およびワイルドカード型が含まれます。

API は宣言と型を慎重に区別します。これは、1 つの宣言が型ファミリ全体を定義できる、ジェネリック型においてもっとも重要です。たとえば、java.util.Set クラスの宣言は次に対応します。

宣言には、ドキュメントコメント、ソース位置、修飾子、および注釈があります。宣言は異なる種類の名前 (簡易、修飾) を持つ場合があります。より詳細な宣言サブクラスが、その構造体に適した追加情報を提供します。たとえば、クラス宣言がコンストラクタおよびスーパークラスへのアクセスを提供します。enum の宣言は、enum 定数を提供するメソッドを持ちます。

TypeMirror は、ソースコード内の戻り値型、パラメータ型などをモデル化するために使用されます。参照型用の TypeMirror は、型から対応する宣言へのマッピング (たとえば、java.util.Set<String> 用のミラー型から java.util.Set 用の宣言へ) を提供します。


FAQ


関連項目


Copyright © 1993, 2013, Oracle and/or its affiliates. All rights reserved.