title: Using Javassist to insert try/finally logic that wraps the original method logic
body: <p>I have a Java 8 project that rewrites bytecode at runtime using Javassist 3.20.0-GA via a custom Java Agent. The goal is to instrument the method such that the original body is wrapped by a try/finally block with print statements. For example, given this trivial method:</p>
  
  <pre><code>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;
      }
  }
  </code></pre>
  
  <p>I would like to output the following modified code (without the comments): </p>
  
  <pre><code>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");
          }
      }
  }
  </code></pre>
  
  <p>First I tried the following code:</p>
  
  <pre><code>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);
  </code></pre>
  
  <p>This appeared to work well for simple void methods without preexisting try/catch/finally blocks, but the output for the <em>getCurrentTime()</em> method was strange, and the <em>System.out.println("Stop")</em> statement was repeated <strong>twice</strong>:</p>
  
  <pre><code>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;
  }
  </code></pre>
  
  <p>The above code "works" when there isn't an error, but pretend <em>System.currentTimeMillis()</em> throws an Exception, then <em>var10</em> would never be set to <em>false</em>, and thusly the <em>System.out.println("Stop")</em> statement would be executed <strong>twice</strong>. Using a boolean flag as a safeguard doesn't work well here, hence I would prefer to simply insert a try/finally at the very beginning and end of the method.</p>
  
  <p>Next I tried instrumenting and replacing the method directly like this:</p>
  
  <pre><code>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+" } }");
      }
  });
  </code></pre>
  
  <p>But that turned into a garbled mess that repeated the <em>"Start"</em> and <em>"Stop"</em> printouts several times across many try/catch/finally blocks (too messy to paste here).</p>
  
  <p>I'm not sure what to try next, or if I'm using the wrong part of the Javassist API. It seems like it should be very straightforward--and it is, with simple void methods--but when values are returned, especially in combination with preexisting try/catch/finally blocks the output becomes unpredictable.</p>
  
  <p>Any thoughts or workarounds? </p>
  
  <p>Thanks in advance.</p>