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

GeeCON Prague 2014 - Having fun with Javassist

GeeCON Prague 2014 - Having fun with Javassist

Anton Arhipov

October 24, 2014
Tweet

More Decks by Anton Arhipov

Other Decks in Programming

Transcript

  1. The Plan for This PrEseNtAtiOn @antonarhipov Prague, 24th October 2014

    Use cases for bytecode manipulation Code examples with Javassist How to brew a Java agent speakerdeck.com/antonarhipov github.com/zeroturnaround/callspy
  2. Bytecode manipulation @antonarhipov Prague, 24th October 2014 Code analysis: Find

    bugs in your application Examine code complexity Find classes by specific attributes / annotations
  3. Bytecode manipulation @antonarhipov Prague, 24th October 2014 Code generation: Lazy

    load data from a database using proxies Add cross-cutting concerns to the code Generate classes from non-Java artefacts
  4. @antonarhipov Prague, 24th October 2014 The main use case for

    Javassist: generate proxies Bytecode manipulation i.e. create a subclass at runtime that intercepts all method invocations java.lang.reflect.Proxy is not enough Hibernate proxies Spring AOP EJB proxies CDI proxies
  5. Bytecode manipulation @antonarhipov Prague, 24th October 2014 Transforming classes without

    source code: Code profiling Code optimisation Some other crazy things…
  6. Bytecode manipulation @antonarhipov Prague, 24th October 2014 … and of

    course, dynamically add logging to application Good news everyone! We’ll implement a logger today!
  7. Logging @antonarhipov Prague, 24th October 2014 public void doSomething(){ //

    no logging here stmt;
 stmt; stmt;
 stmt;
 }

  8. Logging @antonarhipov Prague, 24th October 2014 public void doSomething(){ //

    no logging here // argh!!!
 stmt; stmt;
 stmt;
 }
 If only I could add more logging here…
  9. Javassist @antonarhipov Prague, 24th October 2014 Bytecode manipulation made easy

    Source-level and bytecode-level API Uses vocabulary for a Java language On-the-fly compilation of the injected code www.javassist.org
  10. Javassist @antonarhipov Prague, 24th October 2014 ClassPool CtClass CtMethod CtClass

    CtClass CtClass CtField CtConst CtMethod insertBefore instrument insertAfter
  11. How would you make a tool? A tool should not

    force the user into a special programming model! @antonarhipov Prague, 24th October 2014
  12. @antonarhipov Prague, 24th October 2014 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);! }! }
  13. @antonarhipov Prague, 24th October 2014 public static void premain(String args,

    Instrumentation inst) • java -javaagent:<jarfile>[=options] • META-INF/MANIFEST.MF is required
  14. @antonarhipov Prague, 24th October 2014 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
  15. 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 @antonarhipov Prague, 24th October 2014
  16. 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 @antonarhipov Prague, 24th October 2014
  17. java.lang.instrument.Instrumentation 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);! @antonarhipov Prague, 24th October 2014
  18. public class MyTransformer implements ClassFileTransformer {! public void byte[] transform(ClassLoader

    loader, ! String className,! Class<?> classBeingRedefined,! 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();! }! }!
  19. JRebel Anton Arhipov Prague, 24th October 2014 JRebel core Spring

    plugin Hibernate plugin EJB plugin Reloads classes
  20. JRebel Anton Arhipov Prague, 24th October 2014 JRebel core Spring

    plugin Hibernate plugin EJB plugin Notifies plugins
  21. JRebel Anton Arhipov Prague, 24th October 2014 JRebel core Spring

    plugin Hibernate plugin EJB plugin Reload configurations
  22. JRebel Anton Arhipov Prague, 24th October 2014 JRebel core Spring

    plugin Hibernate plugin EJB plugin Implemented with Javassist