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

イマカラブログ

イマカラメガネの中の人が、芝居と関係あることないこと好き勝手に書くブログ。

スタンドアロンでJDTのASTを使う

f:id:imakaramegane:20170109201859j:plain

必要なライブラリ

JDTのASTをスタンドアロンで使いたい場合は、 Eclipseプラグインが格納されているフォルダにある、 以下のjarを拾ってきてクラスパスを通せば使える (アスタリスク(*)の部分は、実際にはバージョン番号とかになってる)。

Mavenのセントラルリポジトリにも登録されてるので、そこから拾うのが簡単かな。

pom.xmlはこんな感じ。

  <dependencies>
    <dependency>
      <groupId>org.eclipse.core</groupId>
      <artifactId>org.eclipse.core.contenttype</artifactId>
      <version>3.4.100.v20100505-1235</version>
    </dependency>
    <dependency>
      <groupId>org.eclipse.core</groupId>
      <artifactId>org.eclipse.core.jobs</artifactId>
      <version>3.5.100</version>
    </dependency>
    <dependency>
      <groupId>org.eclipse.birt.runtime</groupId>
      <artifactId>org.eclipse.core.resources</artifactId>
      <version>3.10.0.v20150423-0755</version>
    </dependency>
    <dependency>
      <groupId>org.eclipse.core</groupId>
      <artifactId>org.eclipse.core.runtime</artifactId>
      <version>3.7.0</version>
    </dependency>
    <dependency>
      <groupId>org.eclipse.equinox</groupId>
      <artifactId>org.eclipse.equinox.common</artifactId>
      <version>3.6.0.v20100503</version>
    </dependency>
    <dependency>
      <groupId>org.eclipse.equinox</groupId>
      <artifactId>org.eclipse.equinox.preferences</artifactId>
      <version>3.4.1</version>
    </dependency>
    <dependency>
      <groupId>org.eclipse.jdt</groupId>
      <artifactId>org.eclipse.jdt.core</artifactId>
      <version>3.10.0</version>
    </dependency>
    <dependency>
      <groupId>org.eclipse</groupId>
      <artifactId>org.eclipse.osgi</artifactId>
      <version>3.8.0.v20120529-1548</version>
    </dependency>
  </dependencies>

基本的な使い方

ASTParser#createASTを使ってASTを作成。 返却されたASTNodeacceptメソッドにASTVisitorを継承した自作クラスの インスタンスを引き渡してツリーを走査する(Visitorパターン)。

    String source = ...;  // 解析するJavaソースの文字列
    ASTParser parser = ASTParser.newParser( AST.JLS8 );
    Map<?, ?> options = JavaCore.getOptions();
    JavaCore.setComplianceOptions( JavaCore.VERSION_1_8, options );
    parser.setCompilerOptions( options );
    parser.setSource( source.toCharArray() );
    ASTNode ast = parser.createAST( null );
    ast.accept( new ASTVisitor() { ... } );

以下、ソースの断片を説明。

ASTParser#newParser

    ASTParser parser = ASTParser.newParser( AST.JLS8 );

ASTParserインスタンスを作成するときにJavaAPIレベルを指定しないといけないんだけど、 AST.JLS8が全バージョンに対応してるので、 固定でAST.JLS8を指定すればOK。 というか他が全部deprecatedになってるので選択の余地はない。

ASTParser#setCompilerOptions

    Map<?, ?> options = JavaCore.getOptions();
    JavaCore.setComplianceOptions( JavaCore.VERSION_1_8, options );
    parser.setCompilerOptions( options );

解析時に使用されるコンパイラオプションを引数に指定している。 ASTParser#setSource(char[])を使って1.5以降のソースを解析する場合、 このメソッドを使って適切なコンパイラオプションを指定する必要がある。

注意点として、ASTParser#setSourceIClassFileおよびICompilationUnitを引き渡した場合、 設定したコンパイラオプションがリセットされるらしい。

あと、optionsの中身を見るとソースのフォーマットに関するオプションも入ってた。 ASTでソースを改変することがあったら、細かく調べてみようかな。

ASTParser#createAST

    parser.setSource( source.toCharArray() );
    ASTNode ast = parser.createAST( null );

ASTParser#setSourceで設定したソースを解析してASTを構築して返却してくれる。 あとは、返却されたASTNodeインスタンスから各ノードを辿って自分の欲しい情報を 取得する。

返却されたASTNodeはデフォルトだとCompilationUnitインスタンスみたい。 ASTParser#setKindで変えることができるようだけど、必要になったときに調べる。

引数にIProgressMonitorインスタンスを渡せば、解析の進捗状況を確認したり、 途中でキャンセルできるみたい。必要ない場合はnullでOK。

おまけ

ソースファイルの中身を丸っと取得するコード。

    String source = new String(
            Files.readAllBytes( Paths.get( "Hoge.java" ) ), "utf-8" );

参考

blog.cles.jp

(2017/1/10 追記) もっと詳しい情報があった。。。 qiita.com