Slide 1

Slide 1 text

Having fun with Javassist

Slide 2

Slide 2 text

Me Anton Arhipov @antonarhipov We Javassist a lot!

Slide 3

Slide 3 text

You? Are you interested in Javassist? Want to become a better programmer? Bytecode instrumentation, anyone?

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

@Entity
 @Table(name  =  "owners")
 public  class  Owner  extends  Person  {
        @Column(name  =  "address")
        @NotEmpty
        private  String  address;
 
        @Column(name  =  "city")
        @NotEmpty
        private  String  city;
 
        @Column(name  =  "telephone")
        @NotEmpty
        @Digits(fraction  =  0,  integer  =  10)
        private  String  telephone;
 
        @OneToMany(cascade  =  CascadeType.ALL,                                  mappedBy  =  "owner")
        private  Set  pets;  

Slide 6

Slide 6 text

public  class  JavassistLazyInitializer                  extends  BasicLazyInitializer                  implements  MethodHandler  {   final  JavassistLazyInitializer  instance              =  new  JavassistLazyInitializer(…);   
 ProxyFactory  factory  =  new  ProxyFactory();
 factory.setSuperclass(interfaces.length  ==  1?persistentClass:null);
 factory.setInterfaces(interfaces);
 factory.setFilter(FINALIZE_FILTER);   
 Class  cl  =  factory.createClass();
 final  HibernateProxy  proxy  =  (HibernateProxy)  cl.newInstance();
 ((ProxyObject)proxy).setHandler(instance);
 instance.constructed  =  true;
 return  proxy;  

Slide 7

Slide 7 text

public  class  JavassistLazyInitializer                  extends  BasicLazyInitializer                  implements  MethodHandler  {   final  JavassistLazyInitializer  instance              =  new  JavassistLazyInitializer(…);   
 ProxyFactory  factory  =  new  ProxyFactory();
 factory.setSuperclass(interfaces.length  ==  1?persistentClass:null);
 factory.setInterfaces(interfaces);
 factory.setFilter(FINALIZE_FILTER);   
 Class  cl  =  factory.createClass();
 final  HibernateProxy  proxy  =  (HibernateProxy)  cl.newInstance();
 ((ProxyObject)proxy).setHandler(instance);
 instance.constructed  =  true;
 return  proxy;   Generates  proxy!

Slide 8

Slide 8 text

The main use case for bytecode generation in Java framewoks is to generate proxies

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

Agenda Javassist basics -javaagent HacksApplications … and a little bit on the use of Javassist in JRebel

Slide 11

Slide 11 text

Javassist 101 www.javassist.org

Slide 12

Slide 12 text

ClassPool CtClass CtClass CtClass CtClass CtField CtMethod CtConst CtMethod insertBefore insertAfter instrument It feels almost like Java Reflection API :)

Slide 13

Slide 13 text

   public  static  void  main(String[]  args)  throws  Exception  {          ClassPool  cp  =  ClassPool.getDefault();          CtClass  ct  =  cp.makeClass("com.zt.A",                    cp.get("com.zt.Clazz"));          CtMethod[]  methods  =  ct.getMethods();
        for  (CtMethod  method  :  methods)  {
              //…          }          ct.writeFile("/output");    }

Slide 14

Slide 14 text

   public  static  void  main(String[]  args)  throws  Exception  {          ClassPool  cp  =  ClassPool.getDefault();          CtClass  ct  =  cp.makeClass("com.zt.A",                    cp.get("com.zt.Clazz"));          CtMethod[]  methods  =  ct.getMethods();
        for  (CtMethod  method  :  methods)  {
              //…          }          ct.writeFile("/output");    }    ClassPool  cp  =  new  ClassPool(null);      cp.appendSystemPath();  

Slide 15

Slide 15 text

   public  static  void  main(String[]  args)  throws  Exception  {          ClassPool  cp  =  ClassPool.getDefault();          CtClass  ct  =  cp.makeClass("com.zt.A",                    cp.get("com.zt.Clazz"));          CtMethod[]  methods  =  ct.getMethods();
        for  (CtMethod  method  :  methods)  {
              //…          }          ct.writeFile("/output");    }    public  class  A  extends  Clazz  {  
        public  A()  {
        }
    }  

Slide 16

Slide 16 text

   public  static  void  main(String[]  args)  throws  Exception  {          ClassPool  cp  =  ClassPool.getDefault();          CtClass  ct  =  cp.makeClass("com.zt.A",                    cp.get("com.zt.Clazz"));          CtMethod[]  methods  =  ct.getMethods();
        for  (CtMethod  method  :  methods)  {
              //…          }          ct.writeFile("/output");    }

Slide 17

Slide 17 text

   public  static  void  main(String[]  args)  throws  Exception  {          ClassPool  cp  =  ClassPool.getDefault();          CtClass  ct  =  cp.makeClass("com.zt.A",                    cp.get("com.zt.Clazz"));          CtMethod[]  methods  =  ct.getMethods();
        for  (CtMethod  method  :  methods)  {
              //…          }          ct.writeFile("/output");    }  mars:output  anton$  javap  -­‐c  com/zt/A.class  Compiled  from  "A.java"    public  class  com.zt.A  extends  com.zt.Clazz  {        public  com.zt.A();            Code:                0:  aload_0                1:  invokespecial  #10                  4:  return  

Slide 18

Slide 18 text

   public  static  void  main(String[]  args)  throws  Exception  {          ClassPool  cp  =  ClassPool.getDefault();          CtClass  ct  =  cp.makeClass("com.zt.A",                    cp.get("com.zt.Clazz"));          CtMethod[]  methods  =  ct.getMethods();
        for  (CtMethod  method  :  methods)  {
              //…          }          ct.writeFile("/output");    } Can generate classes from metadata at build time

Slide 19

Slide 19 text

   public  static  void  main(String[]  args)  throws  Exception  {          ClassPool  cp  =  ClassPool.getDefault();          cp.appendClassPath(new  ClassPath(){  …  });          CtClass  ct  =  cp.get("com.zt.A");          CtMethod[]  methods  =  ct.getMethods();
        for  (CtMethod  method  :  methods)  {
              //…          }          ct.writeFile("/output");    } … or you can post process the compiled classes

Slide 20

Slide 20 text

   public  static  void  main(String[]  args)  throws  Exception  {          ClassPool  cp  =  ClassPool.getDefault();          CtClass  ctClass  =  cp.get("com.zt.A");          CtMethod  foo  =  ctClass.getMethod("foo",                "()V");          foo.insertBefore("System.out.println();");          Class  c  =  ctClass.toClass();
        A  a  =  (A)  c.newInstance();
        a.foo("Hello");
  }

Slide 21

Slide 21 text

   public  static  void  main(String[]  args)  throws  Exception  {          ClassPool  cp  =  ClassPool.getDefault();          CtClass  ctClass  =  cp.get("com.zt.A");          CtMethod  foo  =  ctClass.getMethod("foo",                "()V");          foo.insertBefore("System.out.println();");          Class  c  =  ctClass.toClass();
        A  a  =  (A)  c.newInstance();
        a.foo("Hello");
  }

Slide 22

Slide 22 text

   public  static  void  main(String[]  args)  throws  Exception  {          ClassPool  cp  =  ClassPool.getDefault();          CtClass  ctClass  =  cp.get("com.zt.A");          CtMethod  foo  =  ctClass.getMethod("foo",                "()V");          foo.insertBefore("System.out.println();");          Class  c  =  ctClass.toClass();
        A  a  =  (A)  c.newInstance();
        a.foo("Hello");
  }    public  void  foo()  {  
    }  

Slide 23

Slide 23 text

   public  static  void  main(String[]  args)  throws  Exception  {          ClassPool  cp  =  ClassPool.getDefault();          CtClass  ctClass  =  cp.get("com.zt.A");          CtMethod  foo  =  ctClass.getMethod("foo",                "(Ljava/lang/String;)V");          foo.insertBefore("System.out.println();");          Class  c  =  ctClass.toClass();
        A  a  =  (A)  c.newInstance();
        a.foo("Hello");
  }    public  void  foo(String  s)  {  
    }  

Slide 24

Slide 24 text

   public  static  void  main(String[]  args)  throws  Exception  {          ClassPool  cp  =  ClassPool.getDefault();          CtClass  ctClass  =  cp.get("com.zt.A");          CtMethod  foo  =  ctClass.getMethod("foo",                "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lja        foo.insertBefore("System.out.println();");          Class  c  =  ctClass.toClass();
        A  a  =  (A)  c.newInstance();
        a.foo("Hello");
  }  Descriptors  might  get  quite  long  ;)  

Slide 25

Slide 25 text

   public  static  void  main(String[]  args)  throws  Exception  {          ClassPool  cp  =  ClassPool.getDefault();          CtClass  ctClass  =  cp.get("com.zt.A");          CtMethod  foo  =  ctClass.getMethod("foo",                "(Ljava/lang/String;)V");          foo.insertBefore("System.out.println($1)");          Class  c  =  ctClass.toClass();
        A  a  =  (A)  c.newInstance();
        a.foo("Hello");
  }  $1,  $2,  $3  —  local  variables    $0  —  this  for  non-­‐static  methods  

Slide 26

Slide 26 text

   public  static  void  main(String[]  args)  throws  Exception  {          ClassPool  cp  =  ClassPool.getDefault();          CtClass  ctClass  =  cp.get("com.zt.A");          CtMethod  foo  =  ctClass.getMethod("foo",                "(Ljava/lang/String;)V");          foo.insertBefore("System.out.println($1)");          Class  c  =  ctClass.toClass();
        A  a  =  (A)  c.newInstance();
        a.foo("Hello");
  }        Exception  in  thread  "main"  javassist.CannotCompileException:  [source  error]  ;  is  missing            at  javassist.CtBehavior.insertBefore(CtBehavior.java:774)            at  javassist.CtBehavior.insertBefore(CtBehavior.java:734)            at  com.zt.basics.Ex.main(Ex.java:35)  

Slide 27

Slide 27 text

   public  static  void  main(String[]  args)  throws  Exception  {          ClassPool  cp  =  ClassPool.getDefault();          CtClass  ctClass  =  cp.get("com.zt.A");          CtMethod  foo  =  ctClass.getMethod("foo",                "(Ljava/lang/String;)V");          foo.insertBefore("System.out.println($1);");          Class  c  =  ctClass.toClass();
        A  a  =  (A)  c.newInstance();
        a.foo("Hello");
  }

Slide 28

Slide 28 text

       CtMethod  foo  =  …          foo.insertBefore(…);          foo.insertAfter(…);   Can implement tracing

Slide 29

Slide 29 text

       CtMethod  foo  =  …          foo.insertBefore(…);          foo.insertAfter(…);   … or add logging

Slide 30

Slide 30 text

       CtMethod  foo  =  …          foo.insertBefore(…);          foo.insertAfter(…);   … or implement AOP

Slide 31

Slide 31 text

       CtMethod  foo  =  …          foo.instrument(new  ExprEditor()  {              @Override
            public  void  edit(NewExpr  e)                        throws  CannotCompileException  {
                e.replace("{"  +
                        "$_  =  $proceed($$);"  +
                        "System.out.println($_);"  +
                        "}");
            }          });

Slide 32

Slide 32 text

       CtMethod  foo  =  …          foo.instrument(new  ExprEditor()  {              @Override
            public  void  edit(NewExpr  e)                        throws  CannotCompileException  {
                e.replace("{"  +
                        "$_  =  $proceed($$);"  +
                        "System.out.println($_);"  +
                        "}");
            }          });

Slide 33

Slide 33 text

       CtMethod  foo  =  …          foo.instrument(new  ExprEditor()  {              @Override
            public  void  edit(NewExpr  e)                        throws  CannotCompileException  {
                e.replace("{"  +
                        "$_  =  $proceed($$);"  +
                        "System.out.println($_);"  +
                        "}");
            }          }); Intercept new instances

Slide 34

Slide 34 text

       CtMethod  foo  =  …          foo.instrument(new  ExprEditor()  {              @Override
            public  void  edit(NewExpr  e)                        throws  CannotCompileException  {
                e.replace("{"  +
                        "$_  =  $proceed($$);"  +
                        "System.out.println($_);"  +
                        "}");
            }          }); Intercept new instances

Slide 35

Slide 35 text

       CtMethod  foo  =  …          foo.instrument(new  ExprEditor()  {              @Override
            public  void  edit(MethodCall  m)                        throws  CannotCompileException  {
                if(m.getMethodName().contains("println"))  {
                    m.replace("{}");
                }                            }          }); Remove unwanted invocations

Slide 36

Slide 36 text

       CtMethod  foo  =  …          foo.instrument(new  ExprEditor()  {              @Override
            public  void  edit(FieldAccess  m)                        throws  CannotCompileException  {
                if  (f.isWriter())  {
                    CtField  field  =  f.getField();
                    String  setterName  =  findSetter(field);
                    f.replace("{"  +  "$0."  +  setterName  +  "($$);"  +  "}");
                }                            }          }); Replace direct field access with setter calls

Slide 37

Slide 37 text

This slide is intentionally left blank

Slide 38

Slide 38 text

Java Agent

Slide 39

Slide 39 text

Java Agent import java.lang.instrument.ClassFileTransformer;   import java.lang.instrument.Instrumentation;   public class Agent {   public static void premain(String args, Instrumentation inst)   throws Exception {   inst.addTransformer(new ClassFileTransformer {   // here be code });   }   } META-­‐INF/MANIFEST.MF   Premain-­‐Class:  Agent $>  java  –javaagent:agent.jar  application.Main

Slide 40

Slide 40 text

ClassFileTransformer new ClassFileTransformer() { public byte[] transform(ClassLoader loader,   String className,   Class classBeingRedefined,   ProtectionDomain protectionDomain,   byte[] classfileBuffer){ ClassPool cp = ClassPool.getDefault();   CtClass ct = cp.makeClass(new   ByteArrayInputStream(classfileBuffer)); // here we can do all the things to ‘ct’ return ct.toBytecode(); }   }

Slide 41

Slide 41 text

new ClassFileTransformer() { public byte[] transform(ClassLoader loader,   String className,   Class classBeingRedefined,   ProtectionDomain protectionDomain,   byte[] classfileBuffer){ ClassPool cp = ClassPool.getDefault();   CtClass ct = cp.makeClass(new   ByteArrayInputStream(classfileBuffer)); // here we can do all the things to ‘ct’ return ct.toBytecode(); }   } ClassFileTransformer

Slide 42

Slide 42 text

new ClassFileTransformer() { public byte[] transform(ClassLoader loader,   String className,   Class classBeingRedefined,   ProtectionDomain protectionDomain,   byte[] classfileBuffer){ ClassPool cp = ClassPool.getDefault();   CtClass ct = cp.makeClass(new   ByteArrayInputStream(classfileBuffer)); // here we can do all the things to ‘ct’ return ct.toBytecode(); }   } ClassFileTransformer

Slide 43

Slide 43 text

new ClassFileTransformer() { public byte[] transform(ClassLoader loader,   String className,   Class classBeingRedefined,   ProtectionDomain protectionDomain,   byte[] classfileBuffer){ ClassPool cp = ClassPool.getDefault();   CtClass ct = cp.makeClass(new   ByteArrayInputStream(classfileBuffer)); // here we can do all the things to ‘ct’ return ct.toBytecode(); }   } ClassFileTransformer

Slide 44

Slide 44 text

No content

Slide 45

Slide 45 text

No content

Slide 46

Slide 46 text

No content

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

https://github.com/zeroturnaround/callspy

Slide 50

Slide 50 text

Javassist in http://0t.ee/javaone-jr

Slide 51

Slide 51 text

JRebel core Spring plugin Hibernate plugin EJB plugin

Slide 52

Slide 52 text

JRebel core Spring plugin Hibernate plugin EJB plugin jrebel.jar

Slide 53

Slide 53 text

Spring plugin Hibernate plugin EJB plugin Reloads classes JRebel core

Slide 54

Slide 54 text

JRebel core Spring plugin Hibernate plugin EJB plugin Notifies plugins

Slide 55

Slide 55 text

JRebel core Spring plugin Hibernate plugin EJB plugin Refresh configurations

Slide 56

Slide 56 text

JRebel core Javassist lives here Spring plugin Hibernate plugin EJB plugin

Slide 57

Slide 57 text

Spring Hibernate OpenEJB JRebel core Spring plugin Hibernate plugin EJB plugin

Slide 58

Slide 58 text

class  Framework  {      public  void  configure(){
    }     } CtClass  framework        =  cp.get("com.zt.Framework"); framework.addInterface(    cp.get("com.zt.jrebel.Listener")); class  Framework      implements  Listener  {      public  void  configure(){
    }     } framework.addMethod(      CtNewMethod.make(          "public  void  onEvent(){"  +          "    configure();"  +          "}",          framework   ));

Slide 59

Slide 59 text

https://github.com/antonarhipov/jpoint HowItWorks

Slide 60

Slide 60 text

No content

Slide 61

Slide 61 text

Your task Javassist

Slide 62

Slide 62 text

https://speakerdeck.com/antonarhipov http://www.slideshare.net/arhan @antonarhipov [email protected] http://0t.ee/javaone-jr