近期有代码检查的项目,用到了抽象语法树,才接触到这类知识点,做个记录
- 根据pom文件引入依赖
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jibx.config.3rdparty.org.eclipse</groupId>
<artifactId>org.eclipse.core.contenttype</artifactId>
<version>3.4.100.v20110423-0524</version>
</dependency>
<dependency>
<groupId>org.jibx.config.3rdparty.org.eclipse</groupId>
<artifactId>org.eclipse.core.jobs</artifactId>
<version>3.5.100.v20110404</version>
</dependency>
<dependency>
<groupId>org.jibx.config.3rdparty.org.eclipse</groupId>
<artifactId>org.eclipse.core.resources</artifactId>
<version>3.7.100.v20110510-0712</version>
</dependency>
<dependency>
<groupId>org.jibx.config.3rdparty.org.eclipse</groupId>
<artifactId>org.eclipse.core.runtime</artifactId>
<version>3.7.0.v20110110</version>
</dependency>
<dependency>
<groupId>org.jibx.config.3rdparty.org.eclipse</groupId>
<artifactId>org.eclipse.equinox.common</artifactId>
<version>3.6.0.v20110523</version>
</dependency>
<dependency>
<groupId>org.jibx.config.3rdparty.org.eclipse</groupId>
<artifactId>org.eclipse.equinox.preferences</artifactId>
<version>3.4.0.v20110502</version>
</dependency>
<dependency>
<groupId>org.eclipse.jdt</groupId>
<artifactId>org.eclipse.jdt.core</artifactId>
<version>3.7.1</version>
</dependency>
<dependency>
<groupId>org.eclipse</groupId>
<artifactId>org.eclipse.osgi</artifactId>
<version>3.8.0.v20120529-1548</version>
</dependency>
- 创建JdtAst类,对java类进行处理,生成一个ASTNode类,强转成CompilationUnit编译单元
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.CompilationUnit;
public class JdtAst {
private ASTParser astParser = ASTParser.newParser(AST.JLS3); // 非常慢
/**
* 获得java源文件的结构CompilationUnit
*/
public CompilationUnit getCompilationUnit(String javaFilePath)
throws Exception {
BufferedInputStream bufferedInputStream = new BufferedInputStream(
new FileInputStream(javaFilePath));
byte[] input = new byte[bufferedInputStream.available()];
bufferedInputStream.read(input);
bufferedInputStream.close();
this.astParser.setSource(new String(input).toCharArray());
/*
* asparser.createAST方法创建返回一个ASTNode类,ASTNode是语法树各节点的抽象基类,
* 它的子类分别代表各种类型的的节点比如CompilationUnit(编译单元), Statement, Expression, Comment,PackageDeclaration等
* 编译单元为一个java文件(可能有多个类)
* */
CompilationUnit result = (CompilationUnit) (this.astParser
.createAST(null)); // 很慢,
return result; //返回CompilationUnit编译单元,
}
}
3 获取类和方法进行处理
import java.util.ArrayList;
import java.util.List;
import com.sun.org.apache.xerces.internal.xs.StringList;
import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;
import org.eclipse.jdt.core.dom.*;
public class testApp {
public static void main(String[] args) throws Exception {
//定义java文件路径
String javaFilePath = "E:\\code\\HolidaysAideService.java";
JdtAst jdt = new JdtAst();
/**
result是使用ASTParser类对Java文件进行解析以后得到的CompilationUnit类的编译单元---- .java文件是一个编译单元,每个编译单元顶多只有public标记的类
.java文件中有几个类,就会编译成几个文件
*
*/
//生成编译单元
CompilationUnit result = jdt.getCompilationUnit(javaFilePath);
List importList = result.imports();// 获取导入的包
//获取第一个类,返回的为list强转成TypeDeclaration类型,后续可以使用TypeDeclaration的方法进行处理,获得方法和返回值等
TypeDeclaration type = (TypeDeclaration) result.types().get(0);
TypeDeclaration[] file=type.getTypes(); //获取全局变量
//获取类中的方法
MethodDeclaration[] methods=type.getMethods();
//对类中方法进行遍历处理,操作方法
for (MethodDeclaration method:methods){
//获得方法的名字 method.getName()为SimpleName类型,不能强转成String可以通过toString转成String类型
String name=method.getName().toString();
System.out.println(name);
//获取方法的内容
Block method_block = method.getBody();
//获取方法的参数
List methodParamertes=method.parameters();
//获取方法的返回值 getReturnType2()为空则为构造函数
if (null!=method.getReturnType2()){
//加入返回值为泛型,如果只要类型不需要具体泛型可以处理(如果为Map<String,String>,只需要具体类型Map)
if (method.getReturnType2().isParameterizedType()){ //判断是否是泛型
//获取类型强转成ParameterizedType,再获得具体类型
//ParameterizedType extends type 都可以通过tostring来转化成String类型
String returnType2=((ParameterizedType)method.getReturnType2()).getType().toString();
}
}else {
System.out.println("为空则该方法为构造函数");
}
//获取javadoc,javadoc为方法前面的/** **/ 单行注释不计入javadoc
Javadoc javadoc=method.getJavadoc();
//获取方法的位置,获取方法起始的位置,包括javadoc,位置的计算为字符为单位,不是以行为单位,如果要以行为单位,可以通过result进行转化
int startPositionByChar=method.getStartPosition(); //会计算出所有的资产,然后得出当前方法的日志的字符的位置
//通过ASTNode换算出行数
int realPosition=result.getLineNumber(startPositionByChar); //行数所在的真正位置
//得出方法的总字符数,也可以通过ASTNode计算出行数来的出方法总共所占的行数
int methodLenth=method.getLength();
//方法总共占的行数
int methodAllLine=result.getLineNumber(startPositionByChar+methodLenth);
List statements = method_block.statements();// 获取方法内容的所有行,一个statement为一行计数而非真正的行数,一个if/else为一行
for (int i=0;i<statements.size();i++){
System.out.println("获取方法内容的所有行"+i+statements.get(i));
}
}
}
}
知识接触面少,暂时记录到此,以后有时间再回顾深入,相关文档记载如下
-
—入门文档
1. Eclipse Corner Article: Abstract Syntax Tree(英文,AST的概述,细节代码不多) -
— 探索Eclipse的ASTParser
ASTParser(中文,相对详细的讲解和代码) -
—AST使用
Eclipse JDT–AST and JavaModel Tutorial(英文,代码很多,但需要有更多的背景知识) -
–使用指南
Eclipse AST 使用指南(pdf文档,更加详细地说明了AST 相关类与方法,可以与eclipse documentation结合使用)
此文为引用,感谢原创,附上链接
https://blog.csdn.net/flying881114/article/details/6187061
https://www.oschina.net/code/piece_full?code=26446