我有一个Java 8项目,它在运行时使用Javassist 3.20.0-GA通过自定义Java代理重写字节码。目标是检测方法,使得原始主体由具有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;
}
}
我想输出以下修改后的代码(没有注释):
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块的简单void方法,但 getCurrentTime()方法的输出很奇怪,并且 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 永远不会被设置为< em> 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块中多次重复“开始”和“停止”打印输出(太乱了,无法粘贴)这里)。
我不确定接下来要尝试什么,或者我使用的是Javassist API的错误部分。看起来它应该非常简单 - 而且,使用简单的void方法 - 但是当返回值时,特别是与预先存在的try / catch / finally块组合时,输出变得不可预测。
有任何想法或解决方法吗?
提前致谢。
答案 0 :(得分:2)
生成的getCurrentTime
是正确的。只有在抛出异常时才输入if(var10)
语句。但在这种情况下,您永远不会达到finally
声明下面的代码。 finally
不捕获异常,只执行一些代码并进一步抛出
生成的代码非常奇怪,但它最终会完成它应该做的事情。消息&#34;停止&#34;将打印一次。