- 追加された行はこの色です。
- 削除された行はこの色です。
// 下階層用テンプレート
#topicpath
----
//ここにコンテンツを記述します。
#contents
**ASTParserとは [#e7a29459]
さてさて、いままでEclipseのウィジェットとか、リスナーとか比較的IDEよりでないところを見てきましたが、今回はソースコードを解析するパーサ、ASTParserを見てみたいと思います。
ASTParserはパッケージエクスプローラなどに表示されているJavaソースからソースコードを取得し解析するとか、ユーザ入力値に応じてJavaのソースコードを生成するとか、Javaソースをプログラマブルに操作するときに使用します。
**やってみる [#nd9bad95]
触ってみましょう。ソースコード情報はパッケージエクスプローラから取得するとして、そのクラスを操作するリーダを作ってみました。
package nu.mine.kino.plugin.astsampless;
import java.util.Iterator;
import org.apache.log4j.Logger;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jdt.core.ICompilationUnit;
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;
import org.eclipse.jdt.core.dom.Javadoc;
import org.eclipse.jdt.core.dom.TagElement;
/**
* Javaソースを解析するリーダーです。
*
* @author Masatomi KINO
* @version $Revision$
*/
public class SourceReader {
private static final Logger logger = Logger.getLogger(SourceReader.class);
private final ICompilationUnit element;
public SourceReader(ICompilationUnit element) {
this.element = element;
}
/**
* 渡されたソースコードの解析を行います。
*/
public void read() {
logger.debug("execute() - start");
ASTParser parser = ASTParser.newParser(AST.JLS3);
parser.setSource(element);
CompilationUnit unit = (CompilationUnit) parser
.createAST(new NullProgressMonitor());
unit.accept(new ASTVisitorImpl());
logger.debug("execute() - end");
}
/**
* ソースを走査するVisitorの実装クラスです。
*
* @author Masatomi KINO
* @version $Revision$
*/
class ASTVisitorImpl extends ASTVisitor {
private final Logger logger = Logger.getLogger(ASTVisitorImpl.class);
public boolean visit(Javadoc node) {
logger.debug("visit(Javadoc) - start");
logger.debug(node);
Iterator iterator = node.tags().iterator();
while (iterator.hasNext()) {
TagElement element = (TagElement) iterator.next();
logger.debug("型:" + element.getClass().getName());
logger.debug("tagname: " + element.getTagName());
logger.debug(element);
}
logger.debug("visit(Javadoc) - end");
return super.visit(node);
}
}
}
このリーダは、コンストラクタでわたってくるJavaソースモデル(ICompilationUnit)をフィールドに保持しておき、readメソッドでそのフィールドのモデルの解析を行います。
ここで実際に解析を行っているのが、
-org.eclipse.jdt.core.dom.ASTParser;
-org.eclipse.jdt.core.dom.ASTVisitor;
です。ASTParserはJavaのソースを、コード部分やコメント部分、JavaDoc部分や、パッケージやimportなどの要素に分解するパーサです。ASTVisitorインタフェースはいわゆるビジタパタンのビジターインタフェースです。ソースコードをASTParserが解析してくれた結果、ソースは様々な要素に分解されるのですが、このASTVisitorインタフェースはその要素ごとのvisitメソッドがあり、それらを実装することで各要素への処理を行うようになっています。具体的に上のASTVisitorの実装クラスを見てみると
class ASTVisitorImpl extends ASTVisitor {
private final Logger logger = Logger.getLogger(ASTVisitorImpl.class);
public boolean visit(Javadoc node) {
logger.debug("visit(Javadoc) - start");
logger.debug(node);
Iterator iterator = node.tags().iterator();
while (iterator.hasNext()) {
TagElement element = (TagElement) iterator.next();
logger.debug("型:" + element.getClass().getName());
logger.debug("tagname: " + element.getTagName());
logger.debug(element);
}
logger.debug("visit(Javadoc) - end");
return super.visit(node);
}
}
となっていて、ここではJavaDoc要素に関する処理だけを実装してあります。
**ソースを渡して、解析させてみる [#y654fc7d]
ソースを渡すのは拡張ポイント使ってなんとでもできるんで後回し。以下のサンプルソースをさっきのリーダに渡して解析させてみます。
-サンプル
package nu.mine.kino;
import java.util.Date;
import java.util.List;
/**
* クラスコメントです。
* クラスのコメントを記述しています。
* @author m-kino
* @see java.lang.String
*
*/
public class TestMain {
public static void main(String[] args) {
Date date = new Date();
List list = null;
System.out.println("Main.");
}
/**
* helloメソッドのJavaDocコメントです。
* 改行してみた
* @return 文字列。
* @param name 名前。
*/
public String hello(String name) {
System.out.println("Hello "+ name +" .");
return "Hello "+ name +" .";
}
/*
* hello2メソッドのJavaDocコメントです。
* 改行してみた
* @return 文字列。
* @param name 名前。
*/
public String hello2(String name) {
System.out.println("Hello "+ name +" .");
return "Hello "+ name +" .";
}
}
***実行結果 [#p8538c5a]
実行結果は以下のようになりました。
[main] DEBUG - visit(Javadoc) - start
[main] DEBUG - /**
* クラスコメントです。
* クラスのコメントを記述しています。
* @author m-kino
* @see java.lang.String
*/
[main] DEBUG - 型:org.eclipse.jdt.core.dom.TagElement
[main] DEBUG - tagname: null
[main] DEBUG -
* クラスコメントです。
* クラスのコメントを記述しています。
[main] DEBUG - 型:org.eclipse.jdt.core.dom.TagElement
[main] DEBUG - tagname: @author
[main] DEBUG -
* @author m-kino
[main] DEBUG - 型:org.eclipse.jdt.core.dom.TagElement
[main] DEBUG - tagname: @see
[main] DEBUG -
* @see java.lang.String
[main] DEBUG - visit(Javadoc) - end
[main] DEBUG - visit(Javadoc) - start
[main] DEBUG - /**
* helloメソッドのJavaDocコメントです。
* 改行してみた
* @return 文字列。
* @param name 名前。
*/
[main] DEBUG - 型:org.eclipse.jdt.core.dom.TagElement
[main] DEBUG - tagname: null
[main] DEBUG -
* helloメソッドのJavaDocコメントです。
* 改行してみた
[main] DEBUG - 型:org.eclipse.jdt.core.dom.TagElement
[main] DEBUG - tagname: @return
[main] DEBUG -
* @return 文字列。
[main] DEBUG - 型:org.eclipse.jdt.core.dom.TagElement
[main] DEBUG - tagname: @param
[main] DEBUG -
* @param name 名前。
[main] DEBUG - visit(Javadoc) - end
[main] DEBUG nu.mine.kino.plugin.astsampless.SourceReader - execute() - end
[main] DEBUG nu.mine.kino.plugin.astsampless.SampleAction - ----------
[main] DEBUG nu.mine.kino.plugin.astsampless.SampleAction - run(IAction) - end
この結果から、以下のようになってることがわかりますね。
-JavaDocひとつが、org.eclipse.jdt.core.dom.Javadoc インスタンスになっている。
-コメント
/**
* クラスコメントです。
* クラスのコメントを記述しています。
* @author m-kino
* @see java.lang.String
*/
は
* クラスコメントです。
* クラスのコメントを記述しています。
と
* @author m-kino
と
* @see java.lang.String
に分割される。この分割されたオブジェクトはorg.eclipse.jdt.core.dom.Javadoc#tags() で取得可能(org.eclipse.jdt.core.dom.TagElementを格納したListが返る)
**Visitorの他のメソッドもOverrideしてみる [#ac5dfaa4]
Visitorには他のメソッドたとえば
public boolean visit(ImportDeclaration node);
などOverrideできる物がたくさんあります。これらをOverrideしてどのような情報が取得できるか試してみます。
***ImportDeclaration [#j85c5cae]
インポート文を表現するクラスですね。
public boolean visit(ImportDeclaration node) {
logger.debug("ImportDeclaration: " + node.getName());
return super.visit(node);
}
の実行結果は以下の通り。
[main] DEBUG - ImportDeclaration: java.util.Date
[main] DEBUG - ImportDeclaration: java.util.List
一つのimport文に対して一回 public boolean visit(ImportDeclaration node) が呼ばれるんですね。ちなみに
logger.debug("ImportDeclaration: " + node);
とするとimport xxxx; のimportまで取得可能です。
***PackageDeclaration [#nd74c8d6]
パッケージを表現するクラスですね。
実行結果は以下の通り。
[main] - PackageDeclaration: nu.mine.kino
パッケージ名が取得できました。
ちなみに
logger.debug("PackageDeclaration: " + node);
とするとpackage nu.mine.kino; のpackageまで取得可能です。
**関連リンク [#pc0a258d]
-[[EclipseのASTParserを試す>http://www-06.ibm.com/jp/developerworks/opensource/050422/j_os-ast.html]]
----
この記事は
#vote(おもしろかった[1],そうでもない[1])
#comment
#topicpath
SIZE(10){現在のアクセス:&counter;}