Having fun with Javassist
Me
Anton Arhipov
@antonarhipov
We Javassist a lot!
You?
Are you interested in Javassist?
Want to become a better programmer?
Bytecode instrumentation, anyone?
@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<Pet>  pets;  
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;  
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!
The main use case for
bytecode generation
in Java framewoks
is to generate proxies
Agenda
Javassist basics
-javaagent
HacksApplications
… and a little bit on the use of Javassist in JRebel
Javassist 101
www.javassist.org
ClassPool
CtClass
CtClass
CtClass
CtClass
CtField
CtMethod
CtConst
CtMethod
insertBefore
insertAfter
instrument
It feels almost like Java Reflection API :)
   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  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();  
   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()  {

        }

    }  
   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  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  
   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
   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
   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  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  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()  {  

    }  
   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)  {  

    }  
   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  ;)  
   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  
   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)  
   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");

  }
       CtMethod  foo  =  …  
        foo.insertBefore(…);  
        foo.insertAfter(…);  
Can implement tracing
       CtMethod  foo  =  …  
        foo.insertBefore(…);  
        foo.insertAfter(…);  
… or add logging
       CtMethod  foo  =  …  
        foo.insertBefore(…);  
        foo.insertAfter(…);  
… or implement AOP
       CtMethod  foo  =  …  
        foo.instrument(new  ExprEditor()  {  
            @Override

            public  void  edit(NewExpr  e)    
                    throws  CannotCompileException  {

                e.replace("{"  +

                        "$_  =  $proceed($$);"  +

                        "System.out.println($_);"  +

                        "}");

            }  
        });
       CtMethod  foo  =  …  
        foo.instrument(new  ExprEditor()  {  
            @Override

            public  void  edit(NewExpr  e)    
                    throws  CannotCompileException  {

                e.replace("{"  +

                        "$_  =  $proceed($$);"  +

                        "System.out.println($_);"  +

                        "}");

            }  
        });
       CtMethod  foo  =  …  
        foo.instrument(new  ExprEditor()  {  
            @Override

            public  void  edit(NewExpr  e)    
                    throws  CannotCompileException  {

                e.replace("{"  +

                        "$_  =  $proceed($$);"  +

                        "System.out.println($_);"  +

                        "}");

            }  
        }); Intercept new instances
       CtMethod  foo  =  …  
        foo.instrument(new  ExprEditor()  {  
            @Override

            public  void  edit(NewExpr  e)    
                    throws  CannotCompileException  {

                e.replace("{"  +

                        "$_  =  $proceed($$);"  +

                        "System.out.println($_);"  +

                        "}");

            }  
        }); Intercept new instances
       CtMethod  foo  =  …  
        foo.instrument(new  ExprEditor()  {  
            @Override

            public  void  edit(MethodCall  m)    
                    throws  CannotCompileException  {

                if(m.getMethodName().contains("println"))  {

                    m.replace("{}");

                }                
            }  
        }); Remove unwanted
invocations
       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
This slide is intentionally left blank
Java Agent
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
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();
}  
}
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
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
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
https://github.com/zeroturnaround/callspy
Javassist in
http://0t.ee/javaone-jr
JRebel
core
Spring
plugin
Hibernate
plugin
EJB
plugin
JRebel
core
Spring
plugin
Hibernate
plugin
EJB
pluginjrebel.jar
Spring
plugin
Hibernate
plugin
EJB
pluginReloads
classes
JRebel
core
JRebel
core
Spring
plugin
Hibernate
plugin
EJB
pluginNotifies
plugins
JRebel
core
Spring
plugin
Hibernate
plugin
EJB
plugin
Refresh
configurations
JRebel
core
Javassist lives here
Spring
plugin
Hibernate
plugin
EJB
plugin
Spring
Hibernate
OpenEJB
JRebel
core
Spring
plugin
Hibernate
plugin
EJB
plugin
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  
));
https://github.com/antonarhipov/jpoint
HowItWorks
Your task
Javassist
https://speakerdeck.com/antonarhipov
http://www.slideshare.net/arhan
@antonarhipov
anton@zeroturnaround.com
http://0t.ee/javaone-jr

JavaOne 2015 - Having fun with Javassist

  • 1.
    Having fun withJavassist
  • 2.
  • 3.
    You? Are you interestedin Javassist? Want to become a better programmer? Bytecode instrumentation, anyone?
  • 5.
    @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<Pet>  pets;  
  • 6.
    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;  
  • 7.
    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!
  • 8.
    The main usecase for bytecode generation in Java framewoks is to generate proxies
  • 10.
    Agenda Javassist basics -javaagent HacksApplications … anda little bit on the use of Javassist in JRebel
  • 11.
  • 12.
  • 13.
       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");    }
  • 14.
       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();  
  • 15.
       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()  {
        }
    }  
  • 16.
       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");    }
  • 17.
       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  
  • 18.
       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
  • 19.
       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
  • 20.
       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");
  }
  • 21.
       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");
  }
  • 22.
       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()  {  
    }  
  • 23.
       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)  {  
    }  
  • 24.
       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  ;)  
  • 25.
       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  
  • 26.
       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)  
  • 27.
       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");
  }
  • 28.
          CtMethod  foo  =  …          foo.insertBefore(…);          foo.insertAfter(…);   Can implement tracing
  • 29.
          CtMethod  foo  =  …          foo.insertBefore(…);          foo.insertAfter(…);   … or add logging
  • 30.
          CtMethod  foo  =  …          foo.insertBefore(…);          foo.insertAfter(…);   … or implement AOP
  • 31.
          CtMethod  foo  =  …          foo.instrument(new  ExprEditor()  {              @Override
            public  void  edit(NewExpr  e)                        throws  CannotCompileException  {
                e.replace("{"  +
                        "$_  =  $proceed($$);"  +
                        "System.out.println($_);"  +
                        "}");
            }          });
  • 32.
          CtMethod  foo  =  …          foo.instrument(new  ExprEditor()  {              @Override
            public  void  edit(NewExpr  e)                        throws  CannotCompileException  {
                e.replace("{"  +
                        "$_  =  $proceed($$);"  +
                        "System.out.println($_);"  +
                        "}");
            }          });
  • 33.
          CtMethod  foo  =  …          foo.instrument(new  ExprEditor()  {              @Override
            public  void  edit(NewExpr  e)                        throws  CannotCompileException  {
                e.replace("{"  +
                        "$_  =  $proceed($$);"  +
                        "System.out.println($_);"  +
                        "}");
            }          }); Intercept new instances
  • 34.
          CtMethod  foo  =  …          foo.instrument(new  ExprEditor()  {              @Override
            public  void  edit(NewExpr  e)                        throws  CannotCompileException  {
                e.replace("{"  +
                        "$_  =  $proceed($$);"  +
                        "System.out.println($_);"  +
                        "}");
            }          }); Intercept new instances
  • 35.
          CtMethod  foo  =  …          foo.instrument(new  ExprEditor()  {              @Override
            public  void  edit(MethodCall  m)                        throws  CannotCompileException  {
                if(m.getMethodName().contains("println"))  {
                    m.replace("{}");
                }                            }          }); Remove unwanted invocations
  • 36.
          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
  • 37.
    This slide isintentionally left blank
  • 38.
  • 39.
    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
  • 40.
    ClassFileTransformer new ClassFileTransformer() { publicbyte[] 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(); }   }
  • 41.
    new ClassFileTransformer() { publicbyte[] 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
  • 42.
    new ClassFileTransformer() { publicbyte[] 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
  • 43.
    new ClassFileTransformer() { publicbyte[] 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
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
    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   ));
  • 59.
  • 61.
  • 62.