SlideShare a Scribd company logo
1 of 48
Download to read offline
Как и зачем инструментировать
байткод в Java приложениях?
Специально для JUG.ua, 25 мая 2017
@antonarhipov
Антон Архипов
@antonarhipov
Javassist & ASM 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;
Зачем?
Модели программирования (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
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

What's hot

Baocao ltjava
Baocao ltjavaBaocao ltjava
Baocao ltjava
Tnt Ttđ
 
Java весна 2013 лекция 7
Java весна 2013 лекция 7Java весна 2013 лекция 7
Java весна 2013 лекция 7
Technopark
 
Java весна 2013 лекция 6
Java весна 2013 лекция 6Java весна 2013 лекция 6
Java весна 2013 лекция 6
Technopark
 
Java Thread Cronometro
Java Thread CronometroJava Thread Cronometro
Java Thread Cronometro
jubacalo
 

What's hot (20)

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

More from Anton Arhipov

JavaZone 2022 - Building Kotlin DSL.pdf
JavaZone 2022 - Building Kotlin DSL.pdfJavaZone 2022 - Building Kotlin DSL.pdf
JavaZone 2022 - Building Kotlin DSL.pdf
Anton Arhipov
 
Riga DevDays 2017 - The hitchhiker’s guide to Java class reloading
Riga DevDays 2017 - The hitchhiker’s guide to Java class reloadingRiga DevDays 2017 - The hitchhiker’s guide to Java class reloading
Riga DevDays 2017 - The hitchhiker’s guide to Java class reloading
Anton Arhipov
 
Devclub 01/2017 - (Не)адекватное Java-интервью
Devclub 01/2017 - (Не)адекватное Java-интервьюDevclub 01/2017 - (Не)адекватное Java-интервью
Devclub 01/2017 - (Не)адекватное Java-интервью
Anton Arhipov
 

More from Anton Arhipov (20)

JavaZone 2022 - Building Kotlin DSL.pdf
JavaZone 2022 - Building Kotlin DSL.pdfJavaZone 2022 - Building Kotlin DSL.pdf
JavaZone 2022 - Building Kotlin DSL.pdf
 
Idiomatic kotlin
Idiomatic kotlinIdiomatic kotlin
Idiomatic kotlin
 
TechTrain 2019 - (Не)адекватное техническое интервью
TechTrain 2019 - (Не)адекватное техническое интервьюTechTrain 2019 - (Не)адекватное техническое интервью
TechTrain 2019 - (Не)адекватное техническое интервью
 
Build pipelines with TeamCity
Build pipelines with TeamCityBuild pipelines with TeamCity
Build pipelines with TeamCity
 
Build pipelines with TeamCity
Build pipelines with TeamCityBuild pipelines with TeamCity
Build pipelines with TeamCity
 
Devoxx Ukraine 2018 - Kotlin DSL in under an hour
Devoxx Ukraine 2018 - Kotlin DSL in under an hourDevoxx Ukraine 2018 - Kotlin DSL in under an hour
Devoxx Ukraine 2018 - Kotlin DSL in under an hour
 
GeeCON Prague 2018 - Kotlin DSL in under an hour
GeeCON Prague 2018 - Kotlin DSL in under an hourGeeCON Prague 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 and Kotlin DSLBuild pipelines with TeamCity and Kotlin DSL
Build pipelines with TeamCity and Kotlin DSL
 
Build pipelines with TeamCity
Build pipelines with TeamCityBuild pipelines with TeamCity
Build pipelines with TeamCity
 
JavaDay Kiev 2017 - Integration testing with TestContainers
JavaDay Kiev 2017 - Integration testing with TestContainersJavaDay Kiev 2017 - Integration testing with TestContainers
JavaDay Kiev 2017 - Integration testing with TestContainers
 
GeeCON Prague 2017 - TestContainers
GeeCON Prague 2017 - TestContainersGeeCON Prague 2017 - TestContainers
GeeCON Prague 2017 - TestContainers
 
JavaOne 2017 - The hitchhiker’s guide to Java class reloading
JavaOne 2017 - The hitchhiker’s guide to Java class reloadingJavaOne 2017 - The hitchhiker’s guide to Java class reloading
JavaOne 2017 - The hitchhiker’s guide to Java class reloading
 
JavaOne 2017 - TestContainers: integration testing without the hassle
JavaOne 2017 - TestContainers: integration testing without the hassleJavaOne 2017 - TestContainers: integration testing without the hassle
JavaOne 2017 - TestContainers: integration testing without the hassle
 
JavaOne 2017 - The hitchhiker’s guide to Java class reloading
JavaOne 2017 - The hitchhiker’s guide to Java class reloadingJavaOne 2017 - The hitchhiker’s guide to Java class reloading
JavaOne 2017 - The hitchhiker’s guide to Java class reloading
 
JavaZone 2017 - The Hitchhiker’s guide to Java class reloading
JavaZone 2017 - The Hitchhiker’s guide to Java class reloadingJavaZone 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
Riga DevDays 2017 - The hitchhiker’s guide to Java class reloadingRiga DevDays 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
GeeCON 2017 - TestContainers. Integration testing without the hassleGeeCON 2017 - TestContainers. Integration testing without the hassle
GeeCON 2017 - TestContainers. Integration testing without the hassle
 
JEEConf 2017 - The hitchhiker’s guide to Java class reloading
JEEConf 2017 - The hitchhiker’s guide to Java class reloadingJEEConf 2017 - The hitchhiker’s guide to Java class reloading
JEEConf 2017 - The hitchhiker’s guide to Java class reloading
 
JEEConf 2017 - Having fun with Javassist
JEEConf 2017 - Having fun with JavassistJEEConf 2017 - Having fun with Javassist
JEEConf 2017 - Having fun with Javassist
 
Devclub 01/2017 - (Не)адекватное Java-интервью
Devclub 01/2017 - (Не)адекватное Java-интервьюDevclub 01/2017 - (Не)адекватное Java-интервью
Devclub 01/2017 - (Не)адекватное Java-интервью
 

JUG.ua 20170225 - Java bytecode instrumentation

  • 1. Как и зачем инструментировать байткод в Java приложениях? Специально для JUG.ua, 25 мая 2017 @antonarhipov
  • 3.
  • 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;
  • 7.
  • 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
  • 15.
  • 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