Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Con-FESS 2015 - Having Fun With Javassist

Con-FESS 2015 - Having Fun With Javassist

Anton Arhipov

April 14, 2015
Tweet

More Decks by Anton Arhipov

Other Decks in Programming

Transcript

  1. Agenda The use cases for bytecode manipulation Code examples with

    Javassist How to create your own Java agent speakerdeck.com/antonarhipov github.com/zeroturnaround/callspy
  2. Bytecode manipulation Code analysis: Find bugs in your application Examine

    code complexity Find classes by specific attributes / annotations
  3. Bytecode manipulation Code generation: Lazily load data using proxies Add

    cross-cutting concerns to the code Generate classes from non-Java artefacts
  4. Bytecode manipulation Main use case for Javassist: generate proxies i.e.

    at runtime, create a subclass that intercepts all method invocations Spring AOP Hibernate proxies EJB proxies CDI proxies java.lang.reflect.Proxy is not enough
  5. public void doSomething(){ // no logging here // argh!!!
 stmt;

    stmt;
 stmt;
 }
 If only I could add more logging here…
  6. Javassist Bytecode manipulation made easy Source level and bytecode level

    APIs Uses vocabulary of a Java language On-the-fly compilation of injected code www.javassist.org
  7. import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.Instrumentation; public class Agent { public static

    void premain(String args, Instrumentation inst) { inst.addTransformer(new ClassFileTransformer { … }); } public static void agentmain(String args, Instrumentation inst) { premain(args, inst); } }
  8. public static void agentmain(String args, Instrumentation inst) Executed when the

    agent attaches to the running JVM META-INF/MANIFEST.MF is required Requires support for loading agents in JVM Allows adding the code to JVM post-factum
  9. Manifest-Version: 1.0 Ant-Version: Apache Ant 1.8.1 Created-By: 1.7.0_15-b03 (Oracle Corporation)

    Premain-Class: com.zeroturnaround.javarebel.java5.AgentInstall Can-Redefine-Classes: true Boot-Class-Path: jrebel.jar Main-Class: com.zeroturnaround.javarebel.java4.Install Implementation-Title: JRebel Specification-Title: jrebel Specification-Version: 5.4.0 Implementation-Version: 201309021535 Manifest.mf
  10. import com.sun.tools.attach.VirtualMachine; //attach to target VM VirtualMachine vm = VirtualMachine.attach("2177");

    //get system properties in the target VM Properties props = vm.getSystemProperties(); //load agent into the VM vm.loadAgent("agent.jar", "arg1=x,arg2=y"); //detach from VM vm.detach(); http://docs.oracle.com/javase/7/docs/jdk/api/attach/spec/com/sun/tools/attach/VirtualMachine.html
  11. Instrumentation API void addTransformer(ClassFileTransformer transformer, boolean canRetransform); void appendToBootstrapClassLoaderSearch(JarFile jarfile);

    void appendToSystemClassLoaderSearch(JarFile jarfile); Class[] getAllLoadedClasses(); Class[] getInitiatedClasses(ClassLoader loader); void redefineClasses(ClassDefinition... classes); void retransformClasses(Class<?>... classes);
  12. public class MyTransformer implements ClassFileTransformer { public void byte[] transform(ClassLoader

    loader, String className, Class<?> toRefine, ProtectionDomain pd, byte[] classfileBuffer){ ClassPool cp = ClassPool.getDefault(); CtClass ct = cp.makeClass(new ByteArrayInputStream(classfileBuffer)); // transform the bytes as required, // for instance - with Javassist return ct.toBytecode(); } }