アノテーションさえ十分に使いこなせていないが、、javaのlombokライブラリについて調べる機会があったので自分なりにまとめてみる。
lombokは、AST変換というマジックを使ってコンパイラの変換プロセスの中で生成されたAST(抽象構文木)を操作し、アノテーションに対応するコードを差し込んでいるようだった。ソースからざっくりとした流れを追ってみる。
動作の流れ
javacの変換の流れを見てみる。
META-INF/services
のjavax.annotation.processing.Processor
のlombok.launch.AnnotationProcessorHider$AnnotationProcessor
のprocess
が呼ばれる。process
メソッドを見ると、実際の処理はcreateWrappedInstance
メソッドで生成されるオブジェクト(lombok.core.AnnotationProcessor
クラス)に転送される。lombok.core.AnnotationProcessor
のprocess
メソッドからlombok.javac.apt.Processor
のprocess
メソッドが呼ばれる。- その中から、
lombok.javac.JavacTransformer
のtransform
が呼ばれるが、その前にRoundEnvironment
のgetRootElements
メソッドで得られるjavax.lang.model.element.Element
のオブジェクトは、com.sun.tools.javac.tree.
JCCompilationUnit
に変換されている。 transform
メソッドで、JCCompilationUnit
のオブジェクトは.lombok.javac.JavacAST
クラスでラップされ、lombok.javac.JavacTransformer$AnnotationVisitor
でASTをトラバースし、lombok.javac.JavacAnnotationHandler
クラスのハンドラーを呼んで変換される。
Javac AST
非公開API?が使われている。mainメソッドを書き換えてみる。
com.sun.tools.javac.util.List
でappendしてもサイズが増えないのは何故?よくわからない。。上では、最後のBlockの初期化でJCExpressionStatement
を渡している。
Eclipse AST
EclipseのJDTは、XML DOMモデルと同じ考え方の独自のDOMとASTを持っているらしい。DOMと同様な考え方で、コードブロックに任意のStatement
を挿入したりすることができる。以下は、main
メソッドにHello, World
を出力するStatement
を挿入し、コンパイルして実行する例。
Manipulates AST with JDT
CompilationUnit
は、コンパイル単位でソースファイルに該当する。createAST
メソッドでは、ASTNode
クラスのオブジェクトが返ってくるが、CompilationUnit
はASTNode
クラスを継承しているためKindをK_COMPILATION_UNIT
に指定すればキャスト可能である。その後、ASTVisitor
でASTをトラバースし、メソッド定義のブロックにSystem.out.println
のStatement
を差し込んでいる。
jarファイルたち
どのクラスがどのjarに含まれているのかわかりづらかった。簡単に調べられる方法はあるのだろうか。。力技で探していった。
必要だったのは以下のjarたち。
参考リンク
- http://www.programcreek.com/2011/01/best-java-development-tooling-jdt-and-astparser-tutorials/
- http://help.eclipse.org/luna/index.jsp?topic=/org.eclipse.jdt.doc.isv/guide/jdt_api_compile.htm
- https://docs.oracle.com/javase/jp/6/api/javax/tools/JavaCompiler.html
- http://www.docjar.com/docs/api/com/sun/tools/javac/tree/package-index.html
- http://www.coppermine.jp/docs/programming/2014/01/lombok.html
コメント