title: How to avoid 'javassist.CannotCompileException: no method body'
body: <p>I'm using Java instrumentation and <a href="http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/" rel="nofollow">Javassist</a> to insert print statements into methods. This mostly works without errors, but for some class methods (e.g. <code>java.util.TimeZone.getSystemTimeZoneID</code>) I get the following exception:</p>
  
  <pre><code>javassist.CannotCompileException: no method body
          at javassist.CtBehavior.insertBefore(CtBehavior.java:695)
          at javassist.CtBehavior.insertBefore(CtBehavior.java:685)
  </code></pre>
  
  <p>My code attempts to avoid this issue by checking <code>CtBehaviour.isEmpty()</code>, but this makes no difference. Any suggestions on how to avoid this?</p>
  
  <p>Here is a minimal example:</p>
  
  <pre><code>public class ExceptionExample implements ClassFileTransformer {
  
    private static final ClassPool pool = ClassPool.getDefault();
  
    public static void premain(String agentArgument,
        Instrumentation instrumentation) {
      instrumentation.addTransformer(new ExceptionExample());
    }
  
    @Override
    public byte[] transform(final ClassLoader loader, final String className,
        final Class&lt;?&gt; classBeingRedefined,
        final ProtectionDomain protectionDomain, final byte[] classfileBuffer)
        throws IllegalClassFormatException {
  
      String dottedClassName = className.replace('/', '.');
  
      if (dottedClassName.startsWith("java.lang")
          || dottedClassName.startsWith("java.util")) {
  
        try {
          System.out.println("Instrumenting: " + dottedClassName);
          return adjustClass(dottedClassName, classBeingRedefined,
              classfileBuffer);
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
  
      return classfileBuffer;
    }
  
    private byte[] adjustClass(final String className,
        final Class&lt;?&gt; classBeingRedefined, final byte[] classfileBuffer)
        throws IOException, RuntimeException, CannotCompileException {
  
      CtClass cl = null;
  
      try {
        cl = pool.makeClass(new java.io.ByteArrayInputStream(classfileBuffer));
        if (!cl.isInterface()) {
          CtBehavior[] methods = cl.getDeclaredBehaviors();
          for (CtBehavior method : methods) {
            if (!method.isEmpty()) {
              try {
                method
                    .insertBefore(String.format(
                        "System.out.println(\"CALLING: %s\");",
                        method.getLongName()));
              } catch (Throwable t) {
                System.out.println("Error instrumenting " + className + "."
                    + method.getName());
                t.printStackTrace();
              }
            }
          }
          return cl.toBytecode();
        }
      } finally {
        if (cl != null) {
          cl.detach();
        }
      }
      return classfileBuffer;
    }
  }
  </code></pre>
  
  <p>And here's a little class I'm testing against:</p>
  
  <pre><code>public class Main {
  
    public static void main(String[] args) throws Exception {
      Calendar c = Calendar.getInstance();
      System.out.println(c.get(Calendar.YEAR));
    }
  }
  </code></pre>
  
  <p>Example output (abbreviated):</p>
  
  <pre class="lang-none prettyprint-override"><code>Instrumenting: java.util.Calendar
  CALLING: java.util.Calendar.&lt;clinit&gt;()
  CALLING: java.util.Calendar.getInstance()
  Instrumenting: java.util.TimeZone
  Error instrumenting java.util.TimeZone.getSystemTimeZoneID
  javassist.CannotCompileException: no method body
          at javassist.CtBehavior.insertBefore(CtBehavior.java:695)
          at javassist.CtBehavior.insertBefore(CtBehavior.java:685)
          at com.cryptomathic.test.instrument.ExceptionExample.adjustClass(ExceptionExample.java:56)
          at com.cryptomathic.test.instrument.ExceptionExample.transform(ExceptionExample.java:34)
          at sun.instrument.TransformerManager.transform(Unknown Source)
          at sun.instrument.InstrumentationImpl.transform(Unknown Source)
          at java.util.Calendar.getInstance(Unknown Source)
          at test.Main.main(Main.java:8)
  Error instrumenting java.util.TimeZone.getSystemGMTOffsetID
  javassist.CannotCompileException: no method body
          at javassist.CtBehavior.insertBefore(CtBehavior.java:695)
          at javassist.CtBehavior.insertBefore(CtBehavior.java:685)
          at com.cryptomathic.test.instrument.ExceptionExample.adjustClass(ExceptionExample.java:56)
          at com.cryptomathic.test.instrument.ExceptionExample.transform(ExceptionExample.java:34)
          at sun.instrument.TransformerManager.transform(Unknown Source)
          at sun.instrument.InstrumentationImpl.transform(Unknown Source)
          at java.util.Calendar.getInstance(Unknown Source)
          at test.Main.main(Main.java:8)
  CALLING: java.util.TimeZone.&lt;clinit&gt;()
  CALLING: java.util.TimeZone.getDefaultRef()
  CALLING: java.util.TimeZone.getDefaultInAppContext()
  CALLING: java.util.TimeZone.setDefaultZone()
  CALLING: java.util.TimeZone.getTimeZone(java.lang.String,boolean)
  CALLING: java.util.TimeZone.setID(java.lang.String)
  ...
  </code></pre>