使用Javassist插入包装原始方法逻辑的try/finally逻辑

使用Javassist插入包装原始方法逻辑的try/finally逻辑,java,bytecode,javassist,Java,Bytecode,Javassist,我有一个Java8项目,它通过自定义Java代理使用Javassist3.20.0-GA在运行时重写字节码。我们的目标是为该方法添加工具,使原始主体被带有print语句的try/finally块包装。例如,给定这个简单的方法: public class TimeService { public long getCurrentTime(){ long time = 0; try { time = System.currentTim

我有一个Java8项目,它通过自定义Java代理使用Javassist3.20.0-GA在运行时重写字节码。我们的目标是为该方法添加工具,使原始主体被带有print语句的try/finally块包装。例如,给定这个简单的方法:

public class TimeService {

    public long getCurrentTime(){

        long time = 0;
        try {
            time = System.currentTimeMillis();
        }
        catch(Throwable t){
            time = -1;
        }

        System.out.println("The current time is "+time);

        return time;
    }
}
我想输出以下修改后的代码(不带注释):

首先,我尝试了以下代码:

CtClass ctClass =  ClassPool.getDefault().get("com.example.test.TimeService");

CtMethod ctMethod = ctClass.getDeclaredMethod("getCurrentTime");

ctMethod.insertBefore("System.out.println(\"Start\");");
ctMethod.insertAfter("System.out.println(\"Stop\");", true);
这似乎适用于没有预先存在try/catch/finally块的简单void方法,但是getCurrentTime()方法的输出很奇怪,并且System.out.println(“Stop”)语句重复了两次

public long getCurrentTime() {
    boolean var10 = false;

    long var10000;
    long var5;
    try {
        var10 = true;
        System.out.println("Start");
        long time = 0L;

        try {
            time = System.currentTimeMillis();
        } catch (Throwable var11) {
            time = -1L;
        }

        System.out.println("The current time is " + time);
        var10000 = time;
        var10 = false;
    } finally {
        if(var10) {
            var5 = 0L;
            System.out.println("Stop");
        }
    }

    var5 = var10000;
    System.out.println("Stop");
    return var5;
}
当没有错误时,上面的代码“工作”,但假设System.currentTimeMillis()抛出异常,那么var10将永远不会被设置为false,因此System.out.println(“Stop”)语句将执行两次。使用布尔标志作为保护在这里不起作用,因此我更愿意在方法的开头和结尾插入try/finally

接下来,我尝试直接插入并替换该方法,如下所示:

CtClass ctClass = ClassPool.getDefault().get("com.example.test.TimeService");

CtMethod ctMethod = ctClass.getDeclaredMethod("getCurrentTime");

ctMethod.instrument(new ExprEditor(){
    public void edit(MethodCall m) throws CannotCompileException {
        String start = "{ System.out.println(\"Start\"); }";
        String stop = "{ System.out.println(\"Stop\"); }";

        m.replace("{ try {"+start+" $_ = $proceed($$); } finally { "+stop+" } }");
    }
});
但这变成了一团乱麻,在许多try/catch/finally块中多次重复“Start”和“Stop”打印输出(太乱了,无法粘贴到这里)

我不确定下一步要尝试什么,或者是否使用了JavassistAPI的错误部分。它看起来应该非常简单——对于简单的void方法也是如此——但是当返回值时,特别是与先前存在的try/catch/finally块组合时,输出变得不可预测

有什么想法或解决办法吗


提前感谢。

生成的
getCurrentTime
是正确的。只有在抛出异常时,才能输入
if(var10)
语句。但在这种情况下,您将永远无法访问下面的代码
finally
语句<代码>最后不会捕获异常,它只是执行一些代码并抛出更多异常


生成的代码非常奇怪,但它最终完成了它应该做的事情。消息“停止”将只打印一次

我重新检查了生成的代码,您是正确的。我真希望生成的代码不是原始代码的倍数(我已经看到10行扩展成100多行)。然后再次生成是非常奇怪的。我也在做类似的事情,但我怀疑每一行都被包装在try/finally中,因此出现了气球和多个打印输出。
CtClass ctClass = ClassPool.getDefault().get("com.example.test.TimeService");

CtMethod ctMethod = ctClass.getDeclaredMethod("getCurrentTime");

ctMethod.instrument(new ExprEditor(){
    public void edit(MethodCall m) throws CannotCompileException {
        String start = "{ System.out.println(\"Start\"); }";
        String stop = "{ System.out.println(\"Stop\"); }";

        m.replace("{ try {"+start+" $_ = $proceed($$); } finally { "+stop+" } }");
    }
});