我有一个Java 8项目,它在运行时使用Javassist 3.20.0-GA通过自定义Java代理重写字节码。我们的目标是测试方法,以便通过带有打印语句的try/finally块来包装原始主体。例如,给定此琐碎方法:使用Javassist插入包装原始方法逻辑的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;
}
}
我想输出下面的修改后的代码(没有注释):
public class TimeService {
public long getCurrentTime(){
try {
System.out.println("Start");
// BEGIN original code
long time = 0;
try {
time = System.currentTimeMillis();
}
catch(Throwable t){
time = -1;
}
System.out.println("The current time is "+time);
return time;
// END original code
}
finally {
System.out.println("Stop");
}
}
}
首先我尝试以下的代码:
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块的简单无效方法,但方法的输出为getCurrentTime()方法为str安格和的System.out.println(“停止”)语句重复两次:
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永远不会被设置为假,正是如此的的System.out.println(“停止”)语句将被执行两次。使用布尔标志作为安全措施在这里不起作用,因此我宁愿在方法的开始和结束处插入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+" } }");
}
});
但是,这变成是重复“开始”和乱码一团糟“停止”打印几次在许多尝试/ catch/finally块(在这里粘贴太乱)。
我不确定接下来要尝试什么,或者如果我使用的是Javassist API的错误部分。它似乎应该是非常简单的 - 它是,用简单的无效方法 - 但是当返回值时,特别是与先前存在的try/catch/finally块结合时,输出变得无法预测。
任何想法或解决方法?
在此先感谢。
我重新检查了生成的代码,你是正确的。我希望生成的代码不是原来的倍数(我已经看到10行爆炸成100多行)。然后_generated很奇怪。 – user1661467