JavaコンパイラAPIの概要

16039 ワード

今日はJavaコンパイラAPIの紹介です.文章の一部は「優鋭課」の学習ノートから抜粋しています.
JavaコンパイラAPI
JavaコンパイラAPIは、Java.compilerと呼ばれるJavaモジュールの一部です.このモジュールには、言語モデルおよび注釈処理、およびコンパイラAPIが含まれる.Javaプログラミング言語とコンパイラツールのタイプとモデル宣言を定義し、実行中にアプリケーションコードから呼び出すことができます.アノテーション処理は、Javaコンパイラのプラグインと見なすアノテーションプロセッサにアクセスするのに役立ちます.これにより、アノテーションプロセッサとアノテーション処理ツール環境との間で通信が可能になります.モデル、要素、およびタイプパッケージはJavaプログラミング言語の要素を処理し、utilパッケージはプログラム要素とタイプを処理するのに役立ちます.
コンパイルツール
JAvax.toolsパッケージは、Javaコンパイラとともに使用されるインタフェースとクラスを提供し、実行中にプログラムから呼び出すことができます.クライアントが独自のアプリケーションコードからコンパイラを位置決めおよび実行できるフレームワークを提供します.また、診断への構造的アクセスとファイルアクセスを上書きするためのファイル抽象化のためのサービスプロバイダインタフェース(SPI)も提供されます.ToolProviderクラスは、コンパイラAPIのエントリポイントを提供します.このような方法は、コンパイラのツールプロバイダを特定するためのいくつかの方法を提供します.たとえば、システムにインストールされているコンパイラでサポートされているJavaソースのバージョンリストを簡単に見つけることができます.
1 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
2 for(SourceVersion sv:compiler.getSourceVersions()){
3    System.out.println(sv);
4 }

 
出力は以下の通りです(システムにインストールされているバージョンに従います).
1 RELEASE_3
2 RELEASE_4
3 RELEASE_5
4 RELEASE_6
5 RELEASE_7
6 RELEASE_8
7 RELEASE_9
8 RELEASE_10
9 RELEASE_11

 
この場合、ToolProviderはデフォルトのコンパイラを見つけます.サービスプロバイダメカニズムを使用することで、代替のコンパイラやツールを見つけることもできます.一部のベンダーがJavaコンパイラを提供している場合、jarファイルにはMETA-INF/service/javax.tool.JavaCompilerというファイルが含まれ、com.vendor.VendorJavaCompilerという行が含まれます.jarファイルをクラスパスに挿入し、次のように配置できます.
1 JavaCompiler vendorJavaCompiler =
2    ServiceLoader.load(JavaCompiler.class).iterator().next();

 
ServiceProviderは、Javaのutilクラスの1つで、実行環境に配備されているサービスプロバイダを検索およびロードします.
JavaCompilerを見つけたら、Javaソースコードを使用してさまざまなコンパイル診断タスクを実行できます.この考えを説明するために、まず簡単なクラスを作成します.以下に示します.
1 package com.mano.jcapidemo;
2 import java.util.Random;
3 public class MyClass {
4    public static void main(String[] args){
5       Random r = new Random();
6       System.out.println("Today your Lucky Number is:
7          "+r.nextInt(10));
8    }
9 }

 
Javaソースファイルを作成した後、DiagnosticCollectorという診断コレクタークラスを使用して診断をリストに収集できます.
別のクラスを作成します.このクラスからコンパイラを呼び出して、上記のクラスMyClassをコンパイルし、診断情報をクラスに報告します.すなわち、Javaソースファイルをロードし、Javaコンパイラによってコンパイルするアプリケーションを作成します.ソースコードにエラーがある場合は、ホストアプリケーションに報告してください.
 1 package com.mano.jcapidemo;
 2  
 3 import com.mano.annotation.CustomAnnotation;
 4 import java.util.Set;
 5 import javax.annotation.processing.AbstractProcessor;
 6 import javax.annotation.processing.RoundEnvironment;
 7 import javax.annotation.processing.SupportedAnnotationTypes;
 8 import javax.annotation.processing.SupportedSourceVersion;
 9 import javax.lang.model.SourceVersion;
10 import javax.lang.model.element.Element;
11 import javax.lang.model.element.ElementKind;
12 import javax.lang.model.element.TypeElement;
13 import javax.tools.Diagnostic;
14 @SupportedAnnotationTypes("com.mano.annotation.CustomAnnotation")
15 @SupportedSourceVersion(SourceVersion.RELEASE_10)
16 public class CustomAnnotationProcessor extends
17       AbstractProcessor {
18    public CustomAnnotationProcessor() {
19    }   public Boolean process(Set extends
20           TypeElement> annotations,
21           RoundEnvironment roundEnv) {
22       for (Element e : roundEnv.getElementsAnnotatedWith
23             (CustomAnnotation.class)) {
24          if (e.getKind() != ElementKind.FIELD) {
25             processingEnv.getMessager().printMessage(
26                Diagnostic.Kind.WARNING,
27                "Not a field", e);
28             continue;
29          }
30       }
31       return true;
32    }
33 }

 
 
コンパイラは、診断リスナーとファイルマネージャの2つのサービスに依存します.リスナーが提供されている場合、診断情報はリスナーに提供されます.それ以外の場合は、リスナーに診断情報が表示されます.それ以外の場合、診断は指定されていないフォーマットでフォーマットされ、デフォルトのエラー出力システム(System.err)に指向されます.デフォルトでは、コンパイラツールは標準ファイルマネージャに関連付けられており、その要件を満たす他のファイルマネージャとともに正常に動作します.
アノテーションプロセッサ
コンパイルプロセスには、アノテーションプロセッサも含まれます.アノテーションによって駆動されるコードをコンパイルする追加のプロセスを実行します.処理は一連の順序で行われ、各順序は、前回生成された注釈サブセットを処理する.アノテーション・プロシージャを実装するインタフェースはjavax.annotation.processin.Processorです.インプリメンテーションクラスは、ツールがプロセッサをインスタンス化するためにパラメータのない構造関数を提供する必要があります.インフラストラクチャの処理は、次のようないくつかのプロトコルに従う必要があります.
  • プロセッサクラスの無パラメータ構造関数を使用してアノテーションプロセッサをインスタンス化する.
  • ツールは、適切なProcessingEnvironmentinstanceインスタンスを渡すことによってinitメソッドを呼び出す.
  • これらのツールは、getSupportedAnnotationType()などのプロセスインタフェースによって定義されたメソッドを呼び出します. getSupportedOptions()とgetSupportedSourceVersion()です.これらのメソッドは、各ラウンドで1回呼び出すのではなく、実行ごとに1回呼び出されます.
  • 最後に、プロセスオブジェクト上のプロセス()メソッドが呼び出される.

  • たとえば、簡単なコメントは次のように定義できます.
    1 package com.mano.jcapidemo;
    2 import java.lang.annotation.ElementType;
    3 import java.lang.annotation.Target;
    4 @Target(ElementType.FIELD)
    5 public@interface CustomAnnotation {
    6 }

     
    次のように、フィールド以外の要素にコメントを適用することを警告するための非常に簡単なコメントプロセッサです.
     1 package com.mano.jcapidemo;
     2  
     3 import com.mano.annotation.CustomAnnotation;
     4 import java.util.Set;
     5 import javax.annotation.processing.AbstractProcessor;
     6 import javax.annotation.processing.RoundEnvironment;
     7 import javax.annotation.processing.SupportedAnnotationTypes;
     8 import javax.annotation.processing.SupportedSourceVersion;
     9 import javax.lang.model.SourceVersion;
    10 import javax.lang.model.element.Element;
    11 import javax.lang.model.element.ElementKind;
    12 import javax.lang.model.element.TypeElement;
    13 import javax.tools.Diagnostic;
    14 @SupportedAnnotationTypes("com.mano.annotation.CustomAnnotation")
    15 @SupportedSourceVersion(SourceVersion.RELEASE_10)
    16 public class CustomAnnotationProcessor extends
    17       AbstractProcessor {
    18    public CustomAnnotationProcessor() {
    19    }   public Boolean process(Set extends
    20           TypeElement> annotations,
    21           RoundEnvironment roundEnv) {
    22       for (Element e : roundEnv.getElementsAnnotatedWith
    23             (CustomAnnotation.class)) {
    24          if (e.getKind() != ElementKind.FIELD) {
    25             processingEnv.getMessager().printMessage(
    26                Diagnostic.Kind.WARNING,
    27                "Not a field", e);
    28             continue;
    29          }
    30       }
    31       return true;
    32    }
    33 }

     
    SupportedAnnotationTypeは、アノテーションプロセッサがどのタイプのアノテーションを処理するかを定義し、SupportedSourceVersionはサポートされているバージョンを定義します.まず,処理方法を上書きできるAbstractProcessor抽象クラスを拡張する.処理方法の内部で作成された論理は、注釈を処理するためにどの基準を設定するかを選択するすべてのテクニックを完了しました.これは最終的に注釈の意味を決定する.
    エレメントスキャナ
    要素スキャナは、コンパイル中にすべての言語要素を分析します.アクセス者モードに基づいて構築され、ソースバージョンのパブリケーションに基づいてプログラム要素をデフォルトの動作でスキャンします.例えば、ElementScanner 9は、ソースバージョンRELEASE_に従って9とRELEASE_10はスキャンを行い、ElementScanner 8はそれぞれソースバージョンRELEASE_に従って8スキャンを行います.この2つのクラスはjavax.lang.model.utilpackageで見つけることができます.
    コンパイルツリーAPI Compiler Tree API
    Javaソースファイル全体を抽象構文ツリーに解析する必要がある場合があります.特に、より深い分析を行うためです.JavaコンパイラツリーAPIはこの要件を遵守し、javax.lang.modelパッケージと密接に関連しています.要素スキャナと同じモードで構築され、同様に動作します.鍵クラスはTreePathScannerと呼ばれます.すべてのサブツリーノードにアクセスし、親ノードへのパスを維持するのに役立ちます.特定のノードにアクセスするには、対応するvisitorXYZメソッドを簡単に上書きできます.
    まとめ
    JavaコンパイラAPIは、JavaアプリケーションからJavaコンパイラへのプログラミングアクセスを提供します.明らかに、このAPIはより深い意味を持っており、ここではその内容についてのみ説明します.ただし、このクイック・プレゼンテーションでは、Java Compiler APIの使用を開始するときに検索するコンテンツに関する手がかりが提供される場合があります.
    リファレンス
    Java APIドキュメント