jsr269提供annotation processor,允许我们在编译器编译过程中挂钩子。http://projectlombok.org/ 的许多功能正是基于此实现。
但有时候可能需要解析语法正确,但没有语义的Java文件(比如对工程中的单个java源文件的方法等元素建索引),这个时候jsr269就不能满足需求了。此时,我们只要语法树(ast)就可以了,也就是说不需要编译通过,只需要语法解析,可选的parser我找到了3个:
-- antlr parser
-- eclipse jdt parser
-- javac parser
下面一个例子使用javac parser来获得ast,并采用visitor模式遍历整颗语法树,提取文件中的所有方法。
注意:
需要在classpath中引入jdk的tools.jar
很多类不属于标准api,目前只在openjdk6,7上做过测试
Java代码
package org.jilen;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import com.sun.source.tree.MethodTree;
import com.sun.source.util.TreeScanner;
import com.sun.tools.javac.file.JavacFileManager;
import com.sun.tools.javac.parser.Parser;
import com.sun.tools.javac.parser.ParserFactory;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.util.Context;
public class JDKParser {
private ParserFactory factory;
public JDKParser() {
factory = getParserFactory();
}
public List parseMethodDefs(String file) throws IOException {
JCCompilationUnit unit = parse(file);
MethodScanner scanner = new MethodScanner();
return scanner.visitCompilationUnit(unit, new ArrayList());
}
JCCompilationUnit parse(String file) throws IOException {
Parser parser = factory.newParser(readFile(file), true, false, true);
return parser.parseCompilationUnit();
}
private ParserFactory getParserFactory() {
Context context = new Context();
JavacFileManager.preRegister(context);
ParserFactory factory = ParserFactory.instance(context);
return factory;
}
CharSequence readFile(String file) throws IOException {
FileInputStream fin = new FileInputStream(file);
FileChannel ch = fin.getChannel();
ByteBuffer buffer = ch.map(MapMode.READ_ONLY, 0, ch.size());
return Charset.defaultCharset().decode(buffer);
}
//扫描方法时,把方法名加入到一个list中
static class MethodScanner extends
TreeScanner, List> {
@Override
public List visitMethod(MethodTree node, List p) {
p.add(node.getName().toString());
return p;
}
}
public static void main(String[] args) throws IOException {
JDKParser parser = new JDKParser();
for (String method : parser.parseMethodDefs("User.java")) {
System.out.println(method);
}
}
}
1.parser.parseCompilationUnit();获得语法树
2.MethodScanner扫描整颗语法树,整个扫面其实是fold/reduce过程
http://jilen.iteye.com/blog/1479632