Having fun with
Javassist
JEEConf 2017
@antonarhipov
whoami
Anton Arhipov
@antonarhipov
Javassist inside!
@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;
The main use case for
bytecode generation
in Java frameworks
is to generate proxies
Why?
Programming model (AOP, ORM, итд)
Monitoring agent (NewRelic, XRebel)
Specialized debuggers
Developer tools (JRebel)
Obfuscation (Proguard)
Javassist 101
www.javassist.org
API
ClassPool
CtClass
CtClass
CtClass
CtClass
CtField
CtMethod
CtConst
CtMethod
insertBefore
insertAfter
instrument
https://speakerdeck.com/antonarhipov
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
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
… or add logging
CtMethod foo = …
foo.insertBefore(…);
foo.insertAfter(…);
… or implement AOP
CtMethod foo = …
foo.insertBefore(…);
foo.insertAfter(…);
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 f)
throws CannotCompileException {

if (f.isWriter()) {

CtField field = f.getField();

String setterName = findSetter(field);

f.replace("{" + "$0." + setterName + "($$);" + "}");

}
}
});
Replace direct field access
with setter calls
java.lang.ClassFormatError: LVTT entry
for 'callbackTypes' in class file
com/google/inject/internal/ProxyFactory
does not match any LVT entry
This slide is intentionally left blank
Java agents
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
JRebel
core
Spring
plugin
Hibernate
plugin
EJB
plugin
JRebel
core
Spring
plugin
Hibernate
plugin
EJB
pluginjrebel.jar
Reloads
classes
JRebel
core
Spring
plugin
Hibernate
plugin
EJB
plugin
Notifies
plugins
JRebel
core
Spring
plugin
Hibernate
plugin
EJB
plugin
JRebel
core
Spring
plugin
Hibernate
plugin
EJB
plugin
Refresh
configurations
Javassist lives here
Spring
plugin
Hibernate
plugin
EJB
plugin
JRebel
core
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
This slide is intentionally left blank
Your task
Javassist
https://speakerdeck.com/antonarhipov
http://www.slideshare.net/arhan
@antonarhipov
anton@zeroturnaround.com

JEEConf 2017 - Having fun with Javassist

  • 1.
  • 2.
  • 4.
    @Entity
 @Table(name = "owners")
 publicclass 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;
  • 5.
    public class JavassistLazyInitializer extendsBasicLazyInitializer 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;
  • 6.
    public class JavassistLazyInitializer extendsBasicLazyInitializer 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.
    The main usecase for bytecode generation in Java frameworks is to generate proxies
  • 9.
    Why? Programming model (AOP,ORM, итд) Monitoring agent (NewRelic, XRebel) Specialized debuggers Developer tools (JRebel) Obfuscation (Proguard)
  • 10.
  • 11.
  • 12.
  • 13.
    public static voidmain(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 voidmain(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 voidmain(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 voidmain(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 voidmain(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 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 voidmain(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 voidmain(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 voidmain(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 voidmain(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 voidmain(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 voidmain(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 voidmain(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 voidmain(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 voidmain(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 voidmain(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.
    … or addlogging CtMethod foo = … foo.insertBefore(…); foo.insertAfter(…);
  • 30.
    … or implementAOP CtMethod foo = … foo.insertBefore(…); foo.insertAfter(…);
  • 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 f) 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.
    java.lang.ClassFormatError: LVTT entry for'callbackTypes' in class file com/google/inject/internal/ProxyFactory does not match any LVT entry
  • 38.
    This slide isintentionally left blank
  • 39.
  • 40.
    Java Agent import java.lang.instrument.ClassFileTransformer; importjava.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
  • 41.
    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(); } }
  • 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
  • 44.
    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
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
    class Framework { publicvoid 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 ));
  • 60.
  • 61.
    This slide isintentionally left blank
  • 62.
  • 63.