应用场景:在考试系统中,对每一份编程答案,系统需要计算圈复杂度:默认圈复杂度为1,每一个方法里面有指定代码块:if/while等时,圈复杂度+1
添加依赖
<!-- javaparser-->
<dependency>
<groupId>com.github.javaparser</groupId>
<artifactId>javaparser-core</artifactId>
<version>3.23.0</version> <!-- 请检查并使用最新版本 -->
</dependency>
相关类的源码阅读
StaticJavaParser
StaticJavaParser类是JavaParser库中的一个静态工具类,用于解析、分析和操作Java源代码。它提供了一系列静态方法,可以用来解析Java源代码文件,获取源代码的抽象语法树(AST),以及对AST进行遍历、修改和生成新的源代码。
通过StaticJavaParser类,我们可以方便地将Java源代码解析成AST,然后通过遍历AST来分析源代码的结构和内容。我们也可以修改AST中的节点,然后重新生成新的源代码。
StaticJavaParser类也提供了一些方便的方法,例如parse、parseBodyDeclaration、parseExpression等,用于解析特定类型的Java代码片段。
可以看到和parse方法有关源码如下,参数可以是输入流、文件、文件路径、阅读器、代码段:
public static CompilationUnit parse(final InputStream in) {
return (CompilationUnit)handleResult(newParser().parse(in));
}
public static CompilationUnit parse(final File file) throws FileNotFoundException {
return (CompilationUnit)handleResult(newParser().parse(file));
}
public static CompilationUnit parse(final Path path) throws IOException {
return (CompilationUnit)handleResult(newParser().parse(path));
}
public static CompilationUnit parse(final Reader reader) {
return (CompilationUnit)handleResult(newParser().parse(reader));
}
public static CompilationUnit parse(String code) {
return (CompilationUnit)handleResult(newParser().parse(code));
}
CompilationUnit
CompilationUnit
是 JavaParser 中的一个重要类,表示了 Java 源代码的编译单元,即一个 Java 源代码文件。它包含了该源文件中的所有类、接口、注解、枚举、包声明、导入声明以及它们的注释信息等
MethodDeclaration.class
这个类的主要作用是表示一个方法声明,并提供了一些方法来获取和操作方法的属性,比如返回类型、方法体等。包含的属性有方法的返回类型和代码块。
public class MethodDeclaration extends CallableDeclaration<MethodDeclaration> implements NodeWithType<MethodDeclaration, Type>, NodeWithOptionalBlockStmt<MethodDeclaration>, NodeWithJavadoc<MethodDeclaration>, NodeWithDeclaration, NodeWithSimpleName<MethodDeclaration>, NodeWithParameters<MethodDeclaration>, NodeWithThrownExceptions<MethodDeclaration>, NodeWithTypeParameters<MethodDeclaration>, NodeWithAccessModifiers<MethodDeclaration>, NodeWithAbstractModifier<MethodDeclaration>, NodeWithStaticModifier<MethodDeclaration>, NodeWithFinalModifier<MethodDeclaration>, NodeWithStrictfpModifier<MethodDeclaration>, Resolvable<ResolvedMethodDeclaration> {
private Type type;
@OptionalProperty
private BlockStmt body;
}
Node.findAll()
在当前节点及其子节点中查找特定类型的节点,并将所有找到的节点存储在一个列表中返回
public <T extends Node> List<T> findAll(Class<T> nodeType) {
List<T> found = new ArrayList();
Objects.requireNonNull(found);
this.walk(nodeType, found::add);
return found;
}
不同的代码块也组成了一个类,以IfStmt.class为例,所以可以在每一个method中通过findAll()来找可以增加复杂度的节点,同时让圈复杂度+1
public class IfStmt extends Statement implements NodeWithCondition<IfStmt> {
private Expression condition;
private Statement thenStmt;
@OptionalProperty
private Statement elseStmt;
实现代码
//计算一个java源代码的圈复杂度
private int calculateComplexityForMethod(String filePath) {
AtomicInteger complexity_sum = new AtomicInteger();
try (FileInputStream in = new FileInputStream(filePath)) {
CompilationUnit cu = StaticJavaParser.parse(in);
cu.findAll(MethodDeclaration.class).forEach(method -> {
complexity = 1;
method.findAll(IfStmt.class).forEach(ifStmt -> complexity++);
method.findAll(WhileStmt.class).forEach(whileStmt -> complexity++);
method.findAll(ForStmt.class).forEach(forStmt -> complexity++);
method.findAll(ConditionalExpr.class).forEach(conditionalExpr -> complexity++);
method.findAll(BinaryExpr.class, expr -> expr.getOperator() == BinaryExpr.Operator.AND ||
expr.getOperator() == BinaryExpr.Operator.OR).forEach(binaryExpr -> complexity++);
// System.out.println("Complexity for method " + method.getNameAsString() + ": " + complexity);
complexity_sum.addAndGet(complexity);
});
} catch (Exception e) {
e.printStackTrace();
}
return complexity_sum.get();
}