JDT工具类的使用
1.获取CompilationUnit。这是读取java文件,生成的整个编译单元。是所有AST节点的根节点。
/**JDT方式,获取指定java文件的CompilationUnit * @param javaFilePath java文件的绝对路劲 * @return CompilationUnit * @功能描述: get compilation unit of source code * @方法名称: getCompilationUnit * @创建时间 2021年5月8日 下午2:47:52 * @version V1.0 */ public static CompilationUnit getCompilationUnit(String javaFilePath) { byte[] input = null; try { BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(javaFilePath)); input = new byte[bufferedInputStream.available()]; bufferedInputStream.read(input); bufferedInputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } ASTParser astParser = ASTParser.newParser(AST.JLS3); astParser.setSource(new String(input).toCharArray()); astParser.setKind(ASTParser.K_COMPILATION_UNIT); CompilationUnit result = (CompilationUnit) (astParser.createAST(null)); //result.getImports(); return result; }
2.获取属性和方法
//Java编译单元AST节点类型。这是AST的根的类型 CompilationUnit cu = getCompilationUnit(classPath); //类里面的类型声明的抽象子类,枚举声明以及注释类型声明和节点类型 List<AbstractTypeDeclaration> types = cu.types(); //此处也可直接获取types.get(0) for (AbstractTypeDeclaration type : types) { if (type.getNodeType() == ASTNode.TYPE_DECLARATION) { //返回方法 /*TypeDeclaration typed = (TypeDeclaration) type; MethodDeclaration[] methods = typed.getMethods();*/ //返回所有主体声明 List<BodyDeclaration> bodies = type.bodyDeclarations(); for (BodyDeclaration body : bodies) { //方法 if (body.getNodeType() == ASTNode.METHOD_DECLARATION) { MethodDeclaration method = (MethodDeclaration) body; //method.getName() 方法名 //method.parameters() 请求参数,数组 //method.getReturnType2() 返回参数 //method.getBody() 方法快 //method.getBody().statements() 方法快中的代码列表 } //属性 else if (body.getNodeType() == ASTNode.FIELD_DECLARATION) { FieldDeclaration field = (FieldDeclaration) body; System.out.println("field"); System.out.println(field.toString()); System.out.println(field.getType().toString()); } } } }
3.解析代码
List list = methodDeclaration.getBody().statements();
获取方法的代码块。此时的statements里面,如果有if、try等代码块,则需要再转
/** * 获取代码块 * @param list * @return */ public static ArrayList<MethodInvocation> getMethodInvocationFromCode(List list){ ArrayList<MethodInvocation> finalCode = new ArrayList<MethodInvocation>(); for(int i=0; i < list.size(); i ++){ //try代码块 if(list.get(i) instanceof TryStatement){ //try List ts = ((TryStatement) list.get(i)).getBody().statements(); finalCode.addAll(getMethodInvocationFromCode(ts)); //catch List cs = ((TryStatement) list.get(i)).catchClauses(); finalCode.addAll(getMethodInvocationFromCode(cs)); //finally Block bf = ((TryStatement) list.get(i)).getFinally(); if(bf != null){ List newlist = new ArrayList(); newlist.add(bf); finalCode.addAll(getMethodInvocationFromCode(newlist)); } } //catch的代码块 else if(list.get(i) instanceof CatchClause){ List ts = ((CatchClause) list.get(i)).getBody().statements(); finalCode.addAll(getMethodInvocationFromCode(ts)); } //if代码块 else if(list.get(i) instanceof IfStatement){ IfStatement ifs = (IfStatement) list.get(i); //条件表达式 Expression expression = ifs.getExpression(); //if语句 Statement ifstatement = ifs.getThenStatement(); //else语句 Statement elsestatement = ifs.getElseStatement(); //if(tx.get() != null) if(expression instanceof InfixExpression){ InfixExpression inf = (InfixExpression) expression; //左表达式 Expression l = inf.getLeftOperand(); //右表达式 Expression r = inf.getRightOperand(); //多于2个条件是,其余条件在extendedOperands里面 List other = inf.extendedOperands(); List newlist = new ArrayList(); if(l instanceof MethodInvocation){ newlist.add(l); } if(r instanceof MethodInvocation){ newlist.add(r); } if(other != null && other.size() > 0){ for(int j=0; j < other.size(); j++){ if(other.get(j) instanceof MethodInvocation){ newlist.add(other.get(j)); } } } if(newlist.size() > 0){ finalCode.addAll(getMethodInvocationFromCode(newlist)); } } else{ //if(ts.check()) List newlist = new ArrayList(); newlist.add(expression); finalCode.addAll(getMethodInvocationFromCode(newlist)); } if(ifstatement instanceof Block){ List ts = ((Block) ifstatement).statements(); finalCode.addAll(getMethodInvocationFromCode(ts)); }else{ System.out.println("IfStatement例外"+list.get(i).toString()); } //只有一个else时,直接读Block //有多个else if时,elsestatement会再被分成if和esle if(elsestatement != null){ if(elsestatement instanceof Block){ List ts = ((Block) elsestatement).statements(); finalCode.addAll(getMethodInvocationFromCode(ts)); }else{ List newlist = new ArrayList(); newlist.add(elsestatement); finalCode.addAll(getMethodInvocationFromCode(newlist)); } } } //for代码块 else if(list.get(i) instanceof ForStatement){ Statement statement =((ForStatement) list.get(i)).getBody(); if(statement instanceof Block){ List ts = ((Block) statement).statements(); finalCode.addAll(getMethodInvocationFromCode(ts)); }else{ System.out.println("ForStatement例外"+list.get(i).toString()); } } //do代码块 else if(list.get(i) instanceof DoStatement){ DoStatement ds = (DoStatement) list.get(i); //do块 Statement statement =ds.getBody(); //while块 Expression expression = ds.getExpression(); if(statement instanceof Block){ List ts = ((Block) statement).statements(); finalCode.addAll(getMethodInvocationFromCode(ts)); }else{ System.out.println("DoStatement例外"+list.get(i).toString()); } if(expression != null){ List newlist = new ArrayList(); newlist.add(expression); finalCode.addAll(getMethodInvocationFromCode(newlist)); } } //while代码块 else if(list.get(i) instanceof WhileStatement){ WhileStatement ws = (WhileStatement) list.get(i); //while条件 Expression expression = ws.getExpression(); //while内容 Statement statement =ws.getBody(); if(expression != null){ List newlist = new ArrayList(); newlist.add(expression); finalCode.addAll(getMethodInvocationFromCode(newlist)); } if(statement instanceof Block){ List ts = ((Block) statement).statements(); finalCode.addAll(getMethodInvocationFromCode(ts)); }else{ System.out.println("WhileStatement例外"+list.get(i).toString()); } } //增强型语句,比如foreach else if(list.get(i) instanceof EnhancedForStatement){ Statement statement =((EnhancedForStatement) list.get(i)).getBody(); if(statement instanceof Block){ List ts = ((Block) statement).statements(); finalCode.addAll(getMethodInvocationFromCode(ts)); }else{ System.out.println("EnhancedForStatement例外"+list.get(i).toString()); } } //switch代码块 else if(list.get(i) instanceof SwitchStatement){ //list内是SwitchCase的list List ts = ((SwitchStatement) list.get(i)).statements(); finalCode.addAll(getMethodInvocationFromCode(ts)); } //switch下的每个子元素 else if(list.get(i) instanceof SwitchCase){ //不做处理 System.out.println("SwitchCase代码:"+list.get(i).toString()); } //break else if(list.get(i) instanceof BreakStatement){ //不做处理 System.out.println("BreakStatement代码:"+list.get(i).toString()); } //continue else if(list.get(i) instanceof ContinueStatement){ //不做处理 System.out.println("ContinueStatement代码:"+list.get(i).toString()); } //Synchronized else if(list.get(i) instanceof SynchronizedStatement){ List ts = ((SynchronizedStatement) list.get(i)).getBody().statements(); finalCode.addAll(getMethodInvocationFromCode(ts)); } //Throw else if(list.get(i) instanceof ThrowStatement){ //不做处理 System.out.println("ThrowStatement代码:"+list.get(i).toString()); } //变量声明语句 //声明变量是一个new Class时,进此分支 else if(list.get(i) instanceof VariableDeclarationStatement){ VariableDeclarationStatement v = (VariableDeclarationStatement) list.get(i); finalCode.addAll(getMethodInvocationFromCode(v.fragments())); } //VariableDeclarationStatement的右边碎片 else if(list.get(i) instanceof VariableDeclarationFragment){ VariableDeclarationFragment v = (VariableDeclarationFragment) list.get(i); if(v.getInitializer() != null){ List newlist = new ArrayList(); newlist.add(v.getInitializer()); finalCode.addAll(getMethodInvocationFromCode(newlist)); } } //表达式,变量赋值语句 else if(list.get(i) instanceof ExpressionStatement){ ExpressionStatement expressionStatement = (ExpressionStatement) list.get(i); Expression expression = expressionStatement.getExpression(); if(expression instanceof Assignment){ System.out.println("====="); Assignment assign=(Assignment) expression; System.out.println("左边:"+assign.getLeftHandSide()); System.out.println("符号:"+assign.getOperator()); System.out.println("右边:"+assign.getRightHandSide()); List newlist = new ArrayList(); if(assign.getLeftHandSide() instanceof CastExpression){ CastExpression cas = (CastExpression) assign.getLeftHandSide(); newlist.add(cas.getExpression()); } if(assign.getRightHandSide() instanceof CastExpression){ CastExpression cas = (CastExpression) assign.getRightHandSide(); newlist.add(cas.getExpression()); } if(newlist.size() > 0){ finalCode.addAll(getMethodInvocationFromCode(newlist)); } } else /*if(expression instanceof MethodInvocation)*/{ List newlist = new ArrayList(); newlist.add(expression); finalCode.addAll(getMethodInvocationFromCode(newlist)); } /*else{ System.out.println("ExpressionStatement例外"+list.get(i).toString()); }*/ } //方法调用 else if(list.get(i) instanceof MethodInvocation){ System.out.println("++++"); MethodInvocation methodInvocation = (MethodInvocation) list.get(i); System.out.println(methodInvocation.toString()); System.out.println("属性:"+methodInvocation.getExpression()); System.out.println("方法名:"+methodInvocation.getName()); System.out.println("参数:"+methodInvocation.arguments()); List newlist = new ArrayList(); //ts.get().toString() if(methodInvocation.getExpression() instanceof MethodInvocation || methodInvocation.getExpression() instanceof ClassInstanceCreation){ newlist.add(methodInvocation.getExpression()); }else{ finalCode.add(methodInvocation); } if(methodInvocation.arguments() != null && methodInvocation.arguments().size() > 0){ for(int j = 0; j < methodInvocation.arguments().size(); j ++){ //参数是一个方法,或一个实例化类 if(methodInvocation.arguments().get(j) instanceof MethodInvocation || methodInvocation.arguments().get(j) instanceof ClassInstanceCreation){ newlist.add(methodInvocation.arguments().get(j)); } } } if(newlist.size() > 0){ finalCode.addAll(getMethodInvocationFromCode(newlist)); } } //实例化类 else if(list.get(i) instanceof ClassInstanceCreation){ ClassInstanceCreation classInstanceCreation = (ClassInstanceCreation) list.get(i); //匿名类声明 AnonymousClassDeclaration anonymousClassDeclaration = classInstanceCreation.getAnonymousClassDeclaration(); if(anonymousClassDeclaration != null){ //获取类的属性、方法 List l = anonymousClassDeclaration.bodyDeclarations(); finalCode.addAll(getMethodInvocationFromCode(l)); } } //方法 else if(list.get(i) instanceof MethodDeclaration){ MethodDeclaration methodDeclaration = (MethodDeclaration) list.get(i); List l = methodDeclaration.getBody().statements(); finalCode.addAll(getMethodInvocationFromCode(l)); //方法参数 List pars = methodDeclaration.parameters(); } //父方法调用 else if(list.get(i) instanceof SuperMethodInvocation){ System.out.println("SuperMethodInvocation代码:"+list.get(i).toString()); } //未知??? else if(list.get(i) instanceof EmptyStatement){ //不做处理 System.out.println("EmptyStatement代码:"+list.get(i).toString()); } //Return else if(list.get(i) instanceof ReturnStatement){ //不做处理 } else{ //不做处理 System.out.println("未知代码:"+list.get(i).toString()); } } return finalCode; }
这是解析方法的代码,获取方法内调用其他方法的集合
各种节点对象
CompilationUnit:Java编译单元,是整个源文件,即一个Java文件或class文件,包括前导和尾随空格和注释。它是所有AST节点的根节点。 PackageDeclaration:对应编译单元包声明部分(包括包前的注释注解等)。 ImportDeclaration:对应编译单元import部分。 TypeDeclaration:每个类或接口类型的声明为一个TypeDeclaration 节点,包括注释文档。同一编译单元可以有多个类声明。 BodyDeclaration:类的主体,即类大括号中的内容(不包括大括号本身)。 Block:块,在type中的每个大括号的内容为一个块(包括大括号本身)。 MethodDeclaration:方法,包括方法声明和方法体定义。 SingleVariableDeclaration:方法的参数列表,单形参的变量声明,如“FileNotFoundException e”。 FieldDeclaration:属性声明语句 TypeDeclarationStatement:在类内部将一个类声明包装到一个语句块里,如“{class hh{}}”,此处的“class hh{}”是一个TypeDeclarationStatement节点。 VariableDeclarationStatement:局部变量声明语句。 VariableDeclarationFragment:全局属性或局部变量声明的片段,类型之后的变量名以及初始化部分。 VariableDeclarationExpression:变量声明表达式,如for(int i=0;;)循环中的“int i=0”。区别于方法中的变量声明语句VariableDeclarationStatement EnhancedForStatement :for-each语句。 IfStatement:if语句 ExpressionStatement:表达式语句,执行某操作。如标准输出语句,方法调用等。 ReturnStatement :return语句。 BreakStatement:break语句 WhileStatement:while语句 TryStatement:try语句,包括try(或try-with-resources)块catch块和finally块 ThrowStatement:抛出异常语句 MethodInvocation :方法调用节点 SuperMethodInvocation:调用父类方法 SwitchStatement:switch语句 SwitchCase:case字句或default字句,不包含该字句后的内容,如“case 1:”或“default:”。 SynchronizedStatement:同步控制语句,如synchronized ( new String() ){ } ThisExpression:返回类的引用或在构造器中调用另一个构造函数。 TypeParameter:参数化类型的类型参数,如List<T>中的参数T WildcardType:通配符类型,如List<?> 的“?” UnionType:联合类型(C/C++中特有) AnnotationTypeDeclaration:注解类型节点 AnnotationTypeMemberDeclaration:注解类型节点的成员声明节点,如抽象方法或默认方法。 AnonymousClassDeclaration:内部类声明节点。包括枚举的内部类实现。 ArrayCreation:数组初始化部分的节点。如new int[2]或new int[]{1,2}。(整个数组创建语句“int array[]=new int[]{1,2};”是一个VariableDeclarationStatement节点) ArrayInitializer:数组初始化的赋值部分。如{1,2}。 ArrayAccess:访问数组的节点,如访问索引值为0的数组值:array[0] ArrayType:数组类型节点,如“int[] array;”的int[]部分,这与int array[]是有区别的。后者的类型为PrimitiveType(int型)。 AssertStatement:断言语句(形如:assert Expression [ : Expression ] ;)。assert不常用,一般用于测试。IDE工具默认关闭断言检查功能,即assert在运行时不会生效。 Assignment:赋值语句,如“i=1” BooleanLiteral:布尔值(true/false)。 CharacterLiteral:字符常量值,如‘char’ StringLiteral:字符串常量值,如“String” NumberLiteral:数字常量值,包括int、double、float、long等类型的值 TypeLiteral:类型常量 CastExpression:强制类型转换子句,如(int) 11.0 CatchClause:catch块 ClassInstanceCreation:类实例化的new部分,如“new DemoClass()” ConditionalExpression:条件从句。如“true?1:0” ConstructorInvocation:构造器调用,在构造方法中出现。如“this();” SuperConstructorInvocation:父类构造器调用 ContinueStatement:continue语句 DoStatement:do-while循环语句,如“do{}while(i==0);” EmptyStatement:只有一个结束符号的空语句,即“ ; ” EnumConstantDeclaration:枚举常量,包含常量前的文档注释 EnumDeclaration:枚举类型声明节点,包含Javadoc FieldAccess:一般变量访问语句 SuperFieldAccess:使用关键词super访问父类变量语句 InfixExpression:判断表达式,返回布尔值 Initializer: AST节点类型,形如:[ static ] Block。区别“static int i;”和“static {int i;}”,前者是FieldDeclaration,后者是Initializer InstanceofExpression:instanceof 语句 LabeledStatement:标记语句,用于循环中,如“label:for(;;){for(;;){break label;}}” Modifier:修饰词节点,包括public、protected、private、static、abstract、final、native、synchronized、transient、volatile、strictfp ParameterizedType:参数化类型(泛型)节点 PrimitiveType:原始类型节点,8种Java原始类型加上void类型 ParenthesizedExpression:括号表达式,形如:( Expression ) PrefixExpression :前缀表达式, 如++i; PostfixExpression:后缀表达式,如i++; QualifiedName:完整名,QualifiedName中每一个名为一个独立的SimpleName SimpleName:直接名,simple与qualified的区别:前者只是给出了最后的一项命名,后者给出了完整的命名,如java.io.IOException是QualifiedName,而IOException为SimpleName。类比于相对路径与绝对路径的区别。 *QualifiedType: Type . SimpleName 如类型 "A.B" 可以有两种方式表示: QualifiedType(SimpleType(SimpleName("A")),SimpleName("B")) SimpleType(QualifiedName(SimpleName("A"),SimpleName("B"))) 在ASTView中一般以第二种方式表示。 SimpleType:直接类型,如List<String>中的“List”和“String”分别是一个SimpleType节点。java.lang.String也为SimpleType MarkerAnnotation:标记注解,如@Controller功能同NormalAnnotation的@Controller() NormalAnnotation:标记注解,如@Controller() SingleMemberAnnotation:单值注解,如@Controller(“String”),作用同NormalAnnotation的@Controller(value=”string”)。 MemberValuePair:注解中的赋值对,如@Controller(value="string")中的“value="string"”。 BlockComment:块注释。/* */ LineComment:行注释。// Javadoc:注释文档。 MemberRef:Javadoc中成员引用,如 /** * @see #i * @see #print(int) */ 中的“#i”,其中i是类的成员属性,print(int i)为成员方法。常用的标记有@see、@link。 MethodRef:Javadoc中方法引用。类似于MemberRef。如例@see #print(int)中的“#print(int)”。 MethodRefParameter:Javadoc中引用方法的参数类型。如例@see #print(int)中的“int”。 TextElement:Javadoc中的的文本内容,包含标记名与标记内容之间的空格,不包括注释结束符“/** * */” TagElement:包括标记名和标记内容。如@author leiy。标记内容可以是:TextElement、Name、MethodRef、MemberRef,也可以嵌套一个{TagElement}。
编译单元的属性:PACKAGE、IMPORTS、TYPES(对应编译单元中除了PACKAGE和IMPORTS部分的全部内容)、EnumDeclaration、AnnotationTypeDeclaration 。 TypeDeclaration节点属性:JAVADOC、MODIFIERS、INTERFACE、NAME、TYPE_PARAMETERS、SUPERCLASS_TYPE、SUPER_INTERFACE_TYPES、BODY_DECLARATIONS等 FieldDeclaration节点属性:TYPE、FRAGMENTS、MODIFIERS、JAVADOC等 MethodDeclaration节点属性:JAVADOC、MODIFIERS、CONSTRUCTOR、TYPE_PARAMETERS、RETURN_TYPE2、NAME、RECEIVER_TYPE、RECEIVER_QUALIFIER、PARAMETERS、EXTRA_DIMENSIONS2、THROWN_EXCEPTION_TYPES、BODY。 BODY:方法的主体,即方法大括号中的内容(包括大括号本身)。 STATEMENTS:方法体中STATEMENTS会从第一个非注释行开始,忽略之前的注释,但包含之后的注释。 EXPRESSION:表达式,可以为一个变量或赋值或比较句子。 THEN_STATEMENT:if语句的then处理块 ELSE_STATEMENT:if语句的else处理块 ARGUMENTS:方法的实参