Monday, April 4, 2016

Javassist and code instrumentation

Looking for a way to trace an Error in a static initializer block, I have stumbled upon this http://stackoverflow.com/a/2211150/651288 example of how to dynamically redefine an ExceptionInInitializerError :
import java.lang.instrument.*;
import javassist.*;
import java.io.*;
import java.security.*;

public class InitializerLoggingAgent implements ClassFileTransformer {
  public static void premain(String agentArgs, Instrumentation inst) {
    inst.addTransformer(new InitializerLoggingAgent(), true);
  }

  private final ClassPool pool = new ClassPool(true);

  public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer)  {
    try {
      if (className.equals("java/lang/ExceptionInInitializerError")) {
        CtClass klass = pool.makeClass(new ByteArrayInputStream(classfileBuffer));
        CtConstructor[] ctors = klass.getConstructors();
        for (int i = 0; i < ctors.length; i++) {
          ctors[i].insertAfter("this.printStackTrace();");
        }
        return klass.toBytecode();
      } else {
        return null;
      }
    } catch (Throwable t) {
      return null;
    }
  }
}

http://jboss-javassist.github.io/javassist/tutorial/tutorial.html
Download javassist zip from here http://jboss-javassist.github.io/javassist/ and explode it
Download Ant (Ant? yes, Ant!) from here https://ant.apache.org/bindownload.cgi
Build javassist source and put the javassist.jar file in the lib folder of your project, add it to build classpath.
Follow instructions to jar your JavaAgent with a MANIFEST.MF containing
Manifest-Version: 1.0
Premain-Class: InitializerLoggingAgent
Can-Retransform-Classes: true

run java -javaagent:agentjar.jar MainClass
It works! Your Error is intercepted and stacktrace is printed! No more silently failing static initializers!
If you forget to add "Can-Retransform-Classes: true" in the MANIFEST.MF, you get the infamous "java.lang.UnsupportedOperationException: adding retransformable transformers is not supported in this environment"


No comments: