使用Javassist插入包装原始方法逻辑的try/finally逻辑
我有一个Java8项目,它通过自定义Java代理使用Javassist3.20.0-GA在运行时重写字节码。我们的目标是为该方法添加工具,使原始主体被带有print语句的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
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+" } }");
}
});