SlideShare a Scribd company logo
Как и зачем инструментировать
байткод в Java приложениях?
Специально для JUG.ua, 25 мая 2017
@antonarhipov
Антон Архипов
@antonarhipov
Javassist & ASM inside!
Привет!
JUG.ua 20170225 - Java bytecode instrumentation
@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;
JUG.ua 20170225 - Java bytecode instrumentation
Зачем?
Модели программирования (AOP, ORM, итд)
Специализированные отладчики
Агенты для мониторинга (NewRelic, XRebel)
Инструменты для разработки (JRebel)
Обфускация (Proguard)
итд
Починить
ошибку в
open-source
библиотеке.
Потому, что я
могу!
Как?
java.lang.instrument
-javaagent
ASM, Javassist, Byte Buddy, cglib, итд
Classloaders
ASM
public class Hello {

public static void main(String[] args) {

System.out.println("Hello, World!");

}

}
public class Hello {

public static void main(String[] args) {

System.out.println("Hello, World!");

}

}
> javap -c Hello
Дизассемблировать Hello
public class Hello {

public static void main(String[] args) {

System.out.println("Hello, World!");

}

}
> javap -c Hello
Compiled from "Hello.java"
public class Hello extends java.lang.Object{
public Hello();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3; //String Hello, World!
5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
JUG.ua 20170225 - Java bytecode instrumentation
java -cp asm-all-3.3.1.jar:asm-util-3.3.1.jar 
org.objectweb.asm.util.ASMifierClassVisitor 
Items.class
ASM
“Сделаю всё как хочу”
Приходится писать много кода
Надо понимать Java-байткод
byte
buddy
Class<?> dynamicType = new ByteBuddy()
.subclass(Object.class)
.method(ElementMatchers.named("toString"))
.intercept(FixedValue.value("Hello World!"))
.make()
.load(getClass().getClassLoader())
.getLoaded();
System.out.println(dynamicType.newInstance().toString()); //Hello World!
System.out.println(dynamicType);
//class net.bytebuddy.renamed.java.lang.Object$ByteBuddy$KUZX06bM
Byte Buddy
Модный API
Попурялный / активный проект
“Много магии”
JAVASSIST
API
ClassPool
CtClass
CtClass
CtClass
CtClass
CtField
CtMethod
CtConst
CtMethod
insertBefore
insertAfter
instrument
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");
}
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");

}
Дескрипторы бывают длинноваты ;)
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 — локальные переменные
$0 — this (для виртуальных методов)
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(…);
Можно реализовать
трассировку
… или добавить логирование
… или реализовать свой “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($_);" +

"}");

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

public void edit(MethodCall m)
throws CannotCompileException {

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

m.replace("{}");

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

}
}
});
Javassist
“Простой как тесак”
Неприхотлив в использовании
Производительность - так себе :(
Java-агенты
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 dragons
});
}
}
$> java –javaagent:agent.jar application.Main
META-INF/MANIFEST.MF
Premain-Class: Agent
https://www.youtube.com/watch?v=SY5lMgWlHAw
DEMO
https://github.com/zeroturnaround/callspy
https://github.com/bsideup/javaagent-boilerplate
anton@zeroturnaround.com
@antonarhipov

More Related Content

ODP
C++14 reflections
ODP
Антон Полухин. C++17
PPTX
Programming Java - Lection 03 - Classes - Lavrentyev Fedor
DOCX
Propuesta..sujei
PPTX
Алексей Кутумов, C++ без исключений, часть 3
PPTX
Java осень 2012 лекция 6
PDF
JQuery
PPTX
Java лаб13
C++14 reflections
Антон Полухин. C++17
Programming Java - Lection 03 - Classes - Lavrentyev Fedor
Propuesta..sujei
Алексей Кутумов, C++ без исключений, часть 3
Java осень 2012 лекция 6
JQuery
Java лаб13

What's hot (20)

PDF
Rambler.iOS #8: Чистые unit-тесты
PDF
1- Sourcecode Array
PDF
Тененёв Анатолий, Boost.Asio в алгоритмической торговле
PDF
Sobrecarga e Sobrescrita - Preparatório Certificação - OCAJP7 - Aula 2 - F
DOCX
Baocao ltjava
PPTX
Clang-tidy: путешествие внутрь AST C++
PDF
The core of javascript
PDF
D2D Pizza JS Игорь Ковган "Koa поможет"
PPT
Шаблоны проектирования 2
PPTX
Java весна 2013 лекция 7
PDF
RxSwift 예제로 감잡기
PPTX
Java весна 2013 лекция 6
PDF
Testování prakticky
PDF
Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016
PPTX
OpenResty/Lua 70+ Advanced Programming Skills and Optimization tips
PDF
Java Thread Cronometro
DOCX
Danna y felix 10°
PPT
从问题开始,前端,架构、框架与库的实战
Rambler.iOS #8: Чистые unit-тесты
1- Sourcecode Array
Тененёв Анатолий, Boost.Asio в алгоритмической торговле
Sobrecarga e Sobrescrita - Preparatório Certificação - OCAJP7 - Aula 2 - F
Baocao ltjava
Clang-tidy: путешествие внутрь AST C++
The core of javascript
D2D Pizza JS Игорь Ковган "Koa поможет"
Шаблоны проектирования 2
Java весна 2013 лекция 7
RxSwift 예제로 감잡기
Java весна 2013 лекция 6
Testování prakticky
Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016
OpenResty/Lua 70+ Advanced Programming Skills and Optimization tips
Java Thread Cronometro
Danna y felix 10°
从问题开始,前端,架构、框架与库的实战
Ad

More from Anton Arhipov (20)

PDF
JavaZone 2022 - Building Kotlin DSL.pdf
PDF
Idiomatic kotlin
PDF
TechTrain 2019 - (Не)адекватное техническое интервью
PDF
Build pipelines with TeamCity
PDF
Build pipelines with TeamCity
PDF
Devoxx Ukraine 2018 - Kotlin DSL in under an hour
PDF
GeeCON Prague 2018 - Kotlin DSL in under an hour
PDF
Build pipelines with TeamCity and Kotlin DSL
PDF
Build pipelines with TeamCity
PDF
JavaDay Kiev 2017 - Integration testing with TestContainers
PDF
GeeCON Prague 2017 - TestContainers
PDF
JavaOne 2017 - The hitchhiker’s guide to Java class reloading
PDF
JavaOne 2017 - TestContainers: integration testing without the hassle
PDF
JavaOne 2017 - The hitchhiker’s guide to Java class reloading
PDF
JavaZone 2017 - The Hitchhiker’s guide to Java class reloading
PDF
Riga DevDays 2017 - The hitchhiker’s guide to Java class reloading
PDF
GeeCON 2017 - TestContainers. Integration testing without the hassle
PDF
JEEConf 2017 - The hitchhiker’s guide to Java class reloading
PDF
JEEConf 2017 - Having fun with Javassist
PDF
Devclub 01/2017 - (Не)адекватное Java-интервью
JavaZone 2022 - Building Kotlin DSL.pdf
Idiomatic kotlin
TechTrain 2019 - (Не)адекватное техническое интервью
Build pipelines with TeamCity
Build pipelines with TeamCity
Devoxx Ukraine 2018 - Kotlin DSL in under an hour
GeeCON Prague 2018 - Kotlin DSL in under an hour
Build pipelines with TeamCity and Kotlin DSL
Build pipelines with TeamCity
JavaDay Kiev 2017 - Integration testing with TestContainers
GeeCON Prague 2017 - TestContainers
JavaOne 2017 - The hitchhiker’s guide to Java class reloading
JavaOne 2017 - TestContainers: integration testing without the hassle
JavaOne 2017 - The hitchhiker’s guide to Java class reloading
JavaZone 2017 - The Hitchhiker’s guide to Java class reloading
Riga DevDays 2017 - The hitchhiker’s guide to Java class reloading
GeeCON 2017 - TestContainers. Integration testing without the hassle
JEEConf 2017 - The hitchhiker’s guide to Java class reloading
JEEConf 2017 - Having fun with Javassist
Devclub 01/2017 - (Не)адекватное Java-интервью
Ad

JUG.ua 20170225 - Java bytecode instrumentation

  • 1. Как и зачем инструментировать байткод в Java приложениях? Специально для JUG.ua, 25 мая 2017 @antonarhipov
  • 4. @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;
  • 5. 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;
  • 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;
  • 8. Зачем? Модели программирования (AOP, ORM, итд) Специализированные отладчики Агенты для мониторинга (NewRelic, XRebel) Инструменты для разработки (JRebel) Обфускация (Proguard) итд
  • 11. ASM
  • 12. public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 }
  • 13. public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 } > javap -c Hello Дизассемблировать Hello
  • 14. public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 } > javap -c Hello Compiled from "Hello.java" public class Hello extends java.lang.Object{ public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3; //String Hello, World! 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
  • 16. java -cp asm-all-3.3.1.jar:asm-util-3.3.1.jar org.objectweb.asm.util.ASMifierClassVisitor Items.class
  • 17. ASM “Сделаю всё как хочу” Приходится писать много кода Надо понимать Java-байткод
  • 19. Class<?> dynamicType = new ByteBuddy() .subclass(Object.class) .method(ElementMatchers.named("toString")) .intercept(FixedValue.value("Hello World!")) .make() .load(getClass().getClassLoader()) .getLoaded(); System.out.println(dynamicType.newInstance().toString()); //Hello World! System.out.println(dynamicType); //class net.bytebuddy.renamed.java.lang.Object$ByteBuddy$KUZX06bM
  • 20. Byte Buddy Модный API Попурялный / активный проект “Много магии”
  • 23. 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"); }
  • 24. 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();
  • 25. 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() {
 }
 }
  • 26. 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"); }
  • 27. 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
  • 28. 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"); }
  • 29. 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");
 }
  • 30. 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");
 }
  • 31. 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() { 
 }
  • 32. 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) { 
 }
  • 33. 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");
 } Дескрипторы бывают длинноваты ;)
  • 34. 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 — локальные переменные $0 — this (для виртуальных методов)
  • 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");
 } 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)
  • 36. 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");
 }
  • 37. CtMethod foo = … foo.insertBefore(…); foo.insertAfter(…); Можно реализовать трассировку … или добавить логирование … или реализовать свой “AOP”
  • 38. CtMethod foo = … foo.instrument(new ExprEditor() { @Override
 public void edit(NewExpr e) throws CannotCompileException {
 e.replace("{" +
 "$_ = $proceed($$);" +
 "System.out.println($_);" +
 "}");
 } });
  • 39. CtMethod foo = … foo.instrument(new ExprEditor() { @Override
 public void edit(NewExpr e) throws CannotCompileException {
 e.replace("{" +
 "$_ = $proceed($$);" +
 "System.out.println($_);" +
 "}");
 } });
  • 40. CtMethod foo = … foo.instrument(new ExprEditor() { @Override
 public void edit(NewExpr e) throws CannotCompileException {
 e.replace("{" +
 "$_ = $proceed($$);" +
 "System.out.println($_);" +
 "}");
 } });
  • 41. CtMethod foo = … foo.instrument(new ExprEditor() { @Override
 public void edit(MethodCall m) throws CannotCompileException {
 if(m.getMethodName().contains("println")) {
 m.replace("{}");
 } } });
  • 42. 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 + "($$);" + "}");
 } } });
  • 43. Javassist “Простой как тесак” Неприхотлив в использовании Производительность - так себе :(
  • 45. 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 dragons }); } } $> java –javaagent:agent.jar application.Main META-INF/MANIFEST.MF Premain-Class: Agent