「ASTP・・・なんぞや?」という人は「Javaのソースコードから色々な情報を取得できるライブラリ」程度の認識でいいと思う。
もう少し詳しく知りたい場合は「Eclipse/プラグイン開発のTIPS集/ソースコードを解析するパーサASTParser」 あたりを読めばいいと思う。
セットアップ(?)の仕方は「EclipseのASTParserを単体で使う」が分かりやすい。
とりあえずサンプルコードの紹介と解説をしていく。
文字数の都合上、全てのコードをこのページに貼り付けることができない為、全体を眺めたい場合は、Githubのリポジトリの方を見て欲しい。
下に、サンプルコアとなる2つのファイル Sample1.java と SampleVisitor1.java を貼りつけている。
大雑把に言えば、Sample1.java には
そして、もう一方の SampleVisitor1.java でクラスの情報の取得を行なっている。
Sample1.java
package info.haxahaxa.astparser.sample;
import info.haxahaxa.astparser.Envs;
import info.haxahaxa.astparser.SourceFile;
import info.haxahaxa.astparser.sample.visitor.*;
import java.io.File;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.CompilationUnit;
/**
* クラス名やフィールド,メソッドの概要を表示するサンプル
*
* @author satanabe1
*
*/
public class Sample1 {
private static ASTVisitor visitor = new SampleVisitor1();
public static void main(String[] args) throws Exception {
SourceFile sourceFile = new SourceFile("src" + File.separator
+ "samples" + File.separator + "AntFileGen.java");
CompilationUnit unit;
ASTParser astParser = ASTParser.newParser(AST.JLS4);
// 以下の setBindingsRecovery setStatementsRecovery はおまじない.
// 完成しているソースコードを解析する時は呼ぶ必要ない.
// 詳しく知りたいならば,IMBのASTParser関連のドキュメントとかを参照すべき.
astParser.setBindingsRecovery(true);
astParser.setStatementsRecovery(true);
// 次の setResolveBindings と setEnvironment が重要!!
// setResolveBindings(true) をしておかないとまともに解析はできない.
// setResolveBindings をまともに機能させるために setEnvironment が必要.
astParser.setResolveBindings(true);
// setEnvironment の第一引数にはクラスパスの配列.第二引数にはソースコードを検索するパスの配列
// 第三第四については何も考えず null, true .納得いかない時はIBMのASTPa...
astParser.setEnvironment(Envs.getClassPath(), Envs.getSourcePath(),
null, true);
// 解析対象のソースコードの入力とか
astParser.setUnitName(sourceFile.getFilePath());// なんでもいいから名前を設定しておく
astParser.setSource(sourceFile.getSourceCode().toCharArray());// 解析対象コードを設定する
unit = (CompilationUnit) astParser.createAST(new NullProgressMonitor());
unit.recordModifications();// ASTへの操作履歴のようなものを有効に
// 解析実行
unit.accept(visitor);
}
}
SampleVisitor1.java
package info.haxahaxa.astparser.sample.visitor;
import info.haxahaxa.astparser.PrintUtil;
import java.util.List;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.IVariableBinding;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
/**
* クラス名やフィールド,メソッドの概要を表示するサンプル
*
* @author satanabe1
*
*/
public class SampleVisitor1 extends ASTVisitor {
/**
* クラス宣言が見つかると呼ばれるメソッド
*/
public boolean visit(TypeDeclaration node) {
PrintUtil.printTitle("クラス宣言");
ITypeBinding typeBinding = node.resolveBinding();// 詳細な情報をITypeBindingインスタンスを使って取得したい
ITypeBinding superClass = typeBinding.getSuperclass();// 親クラスの取得
ITypeBinding[] interfaces = typeBinding.getInterfaces();// インターフェースの取得
String className = typeBinding.getBinaryName();// クラス名の取得
int modifiers = typeBinding.getModifiers();// "public static"とかの識別子
PrintUtil.printMessage("ClassName", className);
PrintUtil.printModifiers("Modifiers", modifiers);
PrintUtil.printMessage("SuperClass", superClass.getBinaryName());
PrintUtil.printMessage("Interfaces", interfaces);
return super.visit(node);
}
/**
* フィールド宣言が見つかると呼ばれるメソッド
*/
public boolean visit(FieldDeclaration node) {
PrintUtil.printTitle("フィールド宣言");
PrintUtil.printModifiers("Modifiers", node.getModifiers());
PrintUtil.printMessage("Type", node.getType().toString());
List fragments = node.fragments();
for (Object frg : fragments) {
if (frg instanceof VariableDeclarationFragment) {
IVariableBinding variableBinding = ((VariableDeclarationFragment) frg)
.resolveBinding();
PrintUtil.printMessage("Name", variableBinding.getName());
}
}
return super.visit(node);
}
/**
* メソッド宣言が見つかると呼ばれるメソッド
*/
public boolean visit(MethodDeclaration node) {
PrintUtil.printTitle("メソッド宣言");
PrintUtil.printMessage("MethodName", node.getName()
.getFullyQualifiedName());
PrintUtil.printModifiers("Modifiers", node.getModifiers());
PrintUtil.printMessage("ReturnType", node.getReturnType2() + "");
PrintUtil.printMessage("Parameters", node.parameters().toString());
return super.visit(node);
}
}
Sample1.java のmainメソッド内の処理で注目すべきポイントとしては、
- ASTParserクラスのインスタンスに対してsetResolveBindingsとかsetEnvironmentとかのメソッドで環境設定
- 更に前述のインスタンスに対してsetSourceメソッドで解析対象のソースコードをセット(46行目)
- CompilationUnitのインスタンスを取得してacceptメソッドで解析実行(50行目)
SampleVisitor1.java の注目すべきポイントは2つ。
- ASTVisitorクラスを継承(22行目)
- boolean visit(型名 node) メソッドの宣言 (26/45/64行目)
ここで覚えておくべき事としては、ASTVisitorクラスのvisitメソッドをオーバーライドすることで、
visitメソッドの引数の型に該当するソースコードを解析した時、勝手にそのvisitメソッドが実行されると言うこと。
つまり、自分が解析したい構文のvisitメソッドを作ってやれば簡単に解析できる。
解析に方法についてはもっと詳しいサイトがたくさんあるので、そちらに任せる。
次回からソースコードの変換について紹介しようと思う。