当前位置: 首页 > 知识库问答 >
问题:

JavaParser:解析和生成Java代码

呼延升
2023-03-14

我已经阅读了JavaParser手册,并开始构建自己的示例。我想要实现的是阅读Java代码并在其上插入新的代码行。具体来说,我想在每个ifwhile语句之前初始化一个计数器,并在语句体内部对计数器进行递增。我这样做的目的是为一组指定的运行运行运行新代码,并观察每个分支执行了多少次。我使用JavaParser来解析和添加代码,因为我想自动生成和运行所有东西。

例如,我们有以下简单的代码:

if (x>4) { 
   x=4; 
} 
else { 
   x=4; 
} 
while (i<x) {
   i++;
} 

在解析之后,我想有如下内容:

int countA=0; 
int countB=0;            
if (x>4) { 
   x=4; 
   countA++;
} 
else { 
   x=4; 
   countB++;
} 
int countC=0;
while (i<x) {
   i++;
   countC++;
} 

到目前为止,我的代码是:

public static void main (String[] args) throws Exception {          
              CompilationUnit cu = StaticJavaParser.parse("class X{void x(){" +
              "    if (x>4) {  " +
              "      x=4;  " +
              "    }  " +
              "    else {  " +
              "        x=4;  " +
              "    }  " +
              "    while (i<x) {  " +
              "        i++;  " +
              "    }  " +
              "    }}");
                              
              cu.findAll(Statement.class).forEach(statement -> {             
                  if (statement.isIfStmt()) {
                      //System.out.println(statement.getChildNodes().get(0));
                     // System.out.println(statement.getParentNodeForChildren().toString());
                     // statement.getChildNodes().add(statement.getChildNodes().get(0));
                
                     // System.out.println(statement.toString());
                  }
                  if (statement.isWhileStmt()) {
                     // System.out.println();
                  }
              });
              System.out.println(cu);
            }
}

我尝试过一些东西(推荐的外线),但没有成功。我的主要问题是,我找不到在给定的语句的childNodes末尾注入任何代码行的方法,这应该是计数器的增量,或者在parentnodes末尾注入任何代码行,这将是初始化。有什么方法可以实现我所描述的吗?


共有1个答案

吕永嘉
2023-03-14

代码中的问题如下:

if (statement.isIfStmt()) {

该条件清楚地表明您正在处理if语句,因此实际上无法添加指令。您需要做的是获取n1元素(其中n是if语句的索引),然后使用:

cu.findAll(Statement.class).get(2).asBlockStmt().addStatement("countA++;")

有几种方法可以定义要添加的表达式,为了清晰起见,我在这里使用了一个普通字符串,但请检查工作示例中的实际语法。

暂时你可以使用同样的技术,但它会更复杂。为简单起见,将使用以下方法在方法开头添加计数器声明:

((BlockStmt)cu.findAll(Statement.class).get(6).getParentNode().get()).addStatement(0, new StringLiteralExpr("int b = 1;"));

剥除

  • 所有语句列表中的第六个语句是while循环
  • 此语句的父节点是该方法的主块,是要添加指令的位置
  • 需要将此对象类强制转换为BlockStmt才能使用addStatement方法
  • StringLiteralExpr是Expression的一个子类,在这里用于从字符串创建实例。您还可以探索许多其他不同的实现

我复制了你的代码,制作了一个工作的JUnit 5,这就是我得到的结果

公共类ParserTest{

String counterName = "count";
Integer counterIndex = 1;

@Test
public void main() {

    CompilationUnit cu = StaticJavaParser.parse("class X{void x(){" + "    if (x>4) {  " + "      x=4;  "
            + "    }  " + "    else {  " + "        x=4;  " + "    }  " + "    while (i<x) {  " + "        i++;  "
            + "    }  " + "    }}");

    cu.findAll(Statement.class).forEach(statement -> {
        if (statement.isIfStmt()) {

            // Add counter declaration in main block for the if
            String counterNameAndIndexIf = counterName + counterIndex++;
            // Create expression using StaticJavaParser
            Expression ifCounterExpression = StaticJavaParser
                    .parseVariableDeclarationExpr(" int " + counterNameAndIndexIf + " = 0");
            ((BlockStmt) statement.getParentNode().get()).addStatement(0, ifCounterExpression);

            // Add counter declaration in main block for the else
            String counterNameAndIndexElse = counterName + counterIndex++;
            // Create expression using StaticJavaParser
            Expression elseCounterExpression = StaticJavaParser
                    .parseVariableDeclarationExpr("int " + counterNameAndIndexElse + " = 0");
            ((BlockStmt) statement.getParentNode().get()).addStatement(0, elseCounterExpression);

            // Add if increment
            Expression ifIncrementExpression = StaticJavaParser.parseExpression(counterNameAndIndexIf + "++");
            ((BlockStmt) statement.getChildNodes().get(1)).addStatement(ifIncrementExpression);

            // Add else increment
            Expression elseIncrementExpression = StaticJavaParser.parseExpression(counterNameAndIndexElse + "++");
            ((BlockStmt) statement.getChildNodes().get(2)).addStatement(elseIncrementExpression);
        }
        if (statement.isWhileStmt()) {
            String counterNameAndIndexWhile = counterName + counterIndex++;
            Expression whileCounterExpression = StaticJavaParser
                    .parseVariableDeclarationExpr(" int " + counterNameAndIndexWhile + " = 0");
            ((BlockStmt) statement.getParentNode().get()).addStatement(0, whileCounterExpression);

            // Add while increment
            Expression whileIncrementExpression = StaticJavaParser.parseExpression(counterNameAndIndexWhile + "++");
            ((BlockStmt) statement.getChildNodes().get(1)).addStatement(whileIncrementExpression);

        }
    });
    System.out.println(cu);
}

而结果就是

class X {

void x() {
    int count3 = 0;
    int count2 = 0;
    int count1 = 0;
    if (x > 4) {
        x = 4;
        count1++;
    } else {
        x = 4;
        count2++;
    }
    while (i < x) {
        i++;
        count3++;
    }
}

希望这有帮助。如果您需要关于如何构建这些对象的说明,请告诉我。当然,有更聪明的方法和代码可以被重构,但我想让它尽可能清晰地为您描述。

干杯

编辑:为了支持语句嵌套和声明方法主块中的所有计数器变量,可以使用以下方法

statement.findRootNode().getChildNodes().get(0).getChildNodes().get(1).getChildNodes().get(2)

这种方法将从根开始自上而下,始终指向主块。使用它添加计数器变量。

 类似资料:
  • 问题内容: 我需要以下工具: 方便地解析Java源代码并轻松访问给定的元素。 轻松生成源代码文件,轻松将数据结构转换为代码 有什么好的技巧,库,框架,工具吗?谢谢你的帮助。 问题答案: 从Java 6开始,编译器在JDK中包含一个API。通过它,您可以通过API 访问Java解析器的结果。JDK5以Mirror API 的形式提供了相同的功能。有一个很好的介绍性文章在这里。 我见过的最好的代码生成

  • 本文向大家介绍java 二维码的生成与解析示例代码,包括了java 二维码的生成与解析示例代码的使用技巧和注意事项,需要的朋友参考一下 二维码,是一种采用黑白相间的平面几何图形通过相应的编码算法来记录文字、图片、网址等信息的条码图片。如下图 二维码的特点: 1.  高密度编码,信息容量大 可容纳多达1850个大写字母或2710个数字或1108个字节,或500多个汉字,比普通条码信息容量约高几十倍。

  • 本文向大家介绍python 生成器和迭代器的原理解析,包括了python 生成器和迭代器的原理解析的使用技巧和注意事项,需要的朋友参考一下 一、生成器简介 在python中,生成器是根据某种算法边循环边计算的一种机制。主要就是用于操作大量数据的时候,一般我们会将操作的数据读入内存中处理,可以计算机的内存是比较宝贵的资源,我认为的当要处理的数据超过内存四分之一的大小时就应该使用生成器。 二、生成器有

  • 注: 内容来自官网资料 Java Generated Code 这个页面准确描述 protocol buffer 编译器为任何给定协议定义生成的java代码。proto2和proto3生成的代码之间的任何不同都将被高亮 - 注意在这份文档中描述的是这些生成代码的不同,而不是基本的消息类/接口,后者在两个版本中是相同的。在阅读这份文档之前你应该先阅读 proto2语言指南 和/或 proto3语言指

  • 本文向大家介绍java中利用Dom4j解析和生成XML文档,包括了java中利用Dom4j解析和生成XML文档的使用技巧和注意事项,需要的朋友参考一下 一、前言 dom4j是一套非常优秀的Java开源api,主要用于读写xml文档,具有性能优异、功能强大、和非常方便使用的特点。   另外xml经常用于数据交换的载体,像调用webservice传递的参数,以及数据做同步操作等等,   所以使用dom

  • 本文向大家介绍基于python3生成标签云代码解析,包括了基于python3生成标签云代码解析的使用技巧和注意事项,需要的朋友参考一下 这篇文章主要介绍了基于python3生成标签云代码解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 标签云是现在大数据里面最喜欢使用的一种展现方式,其中在python3下也能实现标签云的效果,贴图如下: ---