2016-12-15 179 views
0

我有一个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块结合时,输出变得无法预测。

任何想法或解决方法?

在此先感谢。

回答

1

生成的getCurrentTime是正确的。只有在抛出异常时才输入if(var10)语句。但在这种情况下,您将永远无法获得finally声明以下的代码。 finally不会捕捉异常,它只是执行一些代码并抛出进一步

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

+0

我重新检查了生成的代码,你是正确的。我希望生成的代码不是原来的倍数(我已经看到10行爆炸成100多行)。然后_generated很奇怪。 – user1661467