SlideShare a Scribd company logo
Koichi Sakata
PONOS Corporation
Bytecode Manipulation
with a Java Agent
and Byte Buddy
About Me
• Koichi Sakata (阪田 浩一)
• KanJava JUG Leader
• Java Champion
• PONOS Corporation
#oc1bcm2
Intended Audience
• Those who want to start manipulating
bytecode
• Not for experts
#oc1bcm3
javac
Java Bytecode
#oc1bcm
.java • Java Code
.class • Bytecode
Gets loaded by JVM
4
What is bytecode manipulation?
• Editing bytecode in the class files
–Add
–Delete
–Replace
#oc1bcm5
Why do we manipulate?
It's fun!
#oc1bcm6
Not Only Fun
• To change code at runtime
–Generate Entity objects in Hibernate
–Create mock objects in Mockito
#oc1bcm7
Bytecode Manipulation
• Hard to manipulate by hand...
– A class file is a binary file
– JVM has a verification process
#oc1bcm8
Bytecode Manipulation Libraries
• Byte Buddy
• Byteman
• Javassist
• cglib
• ASM
• Apache Commons BCEL
#oc1bcm9
Byte Buddy
• http://bytebuddy.net
• Easy-to-use API
• Java 11 Support
• Duke's Choice Award 2015 Winner
#oc1bcm10
Byte Buddy
• Usage in major libraries
–Hibernate
–Mockito
–Jackson
–etc.
#oc1bcm11
Class<?> subClass = new ByteBuddy()
.subclass(Object.class)
.method(ElementMatchers.named("toString"))
.intercept(FixedValue.value("Hello World!"))
.make()
.load(getClass().getClassLoader())
.getLoaded();
Hello World in Byte Buddy
#oc1bcm12
Class<?> subClass = new ByteBuddy()
.subclass(Object.class)
.method(ElementMatchers.named("toString"))
1. Create a subclass of Object
2. Choose the toString()
Hello World in Byte Buddy
#oc1bcm13
.method(ElementMatchers.named("toString"))
.intercept(FixedValue.value("Hello World!"))
1. Intercept toString() to return a fixed
string value "Hello World"
Hello World in Byte Buddy
#oc1bcm14
.make()
.load(getClass().getClassLoader())
.getLoaded();
1. Make a new type (unloaded class)
2. Load the type
3. Get the new loaded class
Hello World in Byte Buddy
#oc1bcm15
Class<?> subClass = new ByteBuddy()
.subclass(Object.class)
.method(ElementMatchers.named("toString"))
.intercept(FixedValue.value("Hello World!"))
.make()
.load(getClass().getClassLoader())
.getLoaded();
Hello World in Byte Buddy
#oc1bcm16
Demo 1
• Run Hello World
–See a generated class
#oc1bcm17
Demo code is available
• http://bit.ly/oc1bcm
–github.com/jyukutyo/SampleCodeForByt
eBuddySeeesion
#oc1bcm18
Usage in Mockito
• SubclassBytecodeGenerator
–mockClass()
#oc1bcm19
How to use BM?
1. Directly in your application
2. At build time via Maven/Gradle
3. With Java Agent
– No need for changing code
– Detachable
#oc1bcm20
Java Agent?
• Do espionage activities in
your application
– Profiling
– Logging
– Changing the target
application itself
#oc1bcm21
Java Agent
• Instrument programs running on the
JVM
–JSR 163: JavaTM Platform Profiling
Architecture
–JVM calls Java Agent method with
proper timing
#oc1bcm22
Create a Java Agent
• Just define methods
–premain() Method
–agentmain() Method
#oc1bcm23
Create a Java Agent
• premain() Method
–Gets called before main() method
• agentmain() Method
–Gets called when the agent is attached
after JVM startup
#oc1bcm24
With Java Agent
We can run bytecode
manipulation code
at runtime
#oc1bcm25
#oc1bcm26
premain()
public static void premain(String agentArgs,
Instrumentation inst)
• Provides opportunity to modify
classes before loading
–Instrumentation class has useful
methods
#oc1bcm27
Premain-Class: com.s.logging.LoggingAgent
Boot-Class-Path: byte-buddy-1.8.22.jar
MANIFEST.MF
#oc1bcm28
Demo 2
• Create a simple Java Agent
#oc1bcm29
Another Example
• Add outputting logs before executing
a particular method on a particular
class
#oc1bcm30
Example
1. Manipulate bytecode before loading
–Use premain()
2. Replace the class file
–Use ByteBuddy
–Not create a subclass
#oc1bcm31
public class Target {
public void foo() {
System.out.println("foo!");
}
public static void main(String[] args) {
new Target().foo();
}
}
Target Class
#oc1bcm32
TypePool pool = TypePool.Default.ofClassPath();
return new ByteBuddy()
.rebase(pool.describe("c.Target").resolve(),
ClassFileLocator.ForClassLoader
.ofClassPath()
)
Replace the class
#oc1bcm33
return new ByteBuddy()
.rebase(...)
• Replace the original implementation with
new one
• Save the original implementation under a
different method name
Replace the class
#oc1bcm34
Enhance Existing Method
• ByteBuddy#subclass()
–Override the method
• ByteBuddy#redefine()
–Replace the implementation
• ByteBuddy#rebase()
–Copy&Rename the method
–Replace the implementation
#oc1bcm35
TypePool pool = TypePool.Default.ofClassPath();
return new ByteBuddy()
.rebase(pool.describe("c.Target")
.resolve(),
• Can't use a class literal
– JVM loads class before changing the class
• Use the TypePool class and describe()
Replace the class
#oc1bcm36
.rebase(pool.describe(...).resolve(),
ClassFileLocator.ForClassLoader
.ofClassPath()
)
• Allow to locate a class file
• ofClassPath() - Scan the running
application's class path
Replace the class
#oc1bcm37
return new ByteBuddy()
...
.method(ElementMatchers.named("foo"))
.intercept(
MethodDelegation
.to(LoggingInterceptor.class)
.andThen(SuperMethodCall.INSTANCE)
)
Intercept the method
#oc1bcm38
Delegation
• MethodDelegation.to()
–Specify a Class to delegate
• A best match method is used
#oc1bcm39
return new ByteBuddy()
...
.method(ElementMatchers.named("foo"))
.intercept(
MethodDelegation
.to(LoggingInterceptor.class)
.andThen(SuperMethodCall.INSTANCE)
)
Intercept the method
#oc1bcm40
public static class LoggingInterceptor {
public static void intercept(
@Origin Method m) {
...println("Call " + m.getName()...);
}
}
Interceptor Class
#oc1bcm41
Delegated Method
• Annotations for Parameter
–@Origin
• Reference to the method/constructor
#oc1bcm42
Delegated Method
• Annotations for Parameter
–@This/@Super
• Dynamic/Super type's instance
–@Argument, @AllArguments
–@SuperCall
• Callable/Runnable instance of the super's
implementation of the method
#oc1bcm43
public static void premain(String args,
Instrumentation inst) {
inst.addTransformer(
new ClassFileTransformer() {
@Override
public byte[] transform(...) {
premain()
#oc1bcm44
public byte[] transform(ClassLoader loader,
String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer) {
// Call ByteBuddy
}
transform()
#oc1bcm45
public byte[] transform(ClassLoader loader,
String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer)
• className – Class name to be loaded
• classfileBuffer – Class file content
transform()
#oc1bcm46
public byte[] transform(ClassLoader loader,
String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer)
• Return the class file content
transform()
#oc1bcm47
Demo 3
• Add outputting logs before executing
a method
#oc1bcm48
#oc1bcm49
Features in ByteBuddy
• Add fields/methods
• Manipulate stack
• Generate CONDY bytecode
– Constant Dynamic – JEP 309
• Simplify Java Agent with AgentBuilder
• lots of other features
#oc1bcm50
Byte Buddy's AgentBuilder
• Simplify the Java Agent
implementation
#oc1bcm51
new AgentBuilder.Default()
.type(ElementMatchers.named("com.sakatakoic
hi.logging.Target"))
.transform(new AgentBuilder.Transformer() {
...
})
.installOn(inst);
AgentBuilder
#oc1bcm52
AgentBuilder
1. Use AgentBuilder
–instead of ByteBuddy class
2. Use AgentBuilder.Transformer
–instead of ClassFileTransformer
3. Call installOn()
#oc1bcm53
.transform(new AgentBuilder.Transformer() {
public DynamicType.Builder<?> transform(
DynamicType.Builder<?> builder,
TypeDescription typeDescription,
ClassLoader classLoader,
JavaModule javaModule) {
return builder
.method(ElementMatch...named("foo"))
.intercept(...);
}
})
Transformer
#oc1bcm54
Without -javaagent
• -javaagent option can be removed
–Call ByteBuddyAgent.install()
–Call AgentBuilder#installOnByteBuddyAgent()
• instead of installOn()
–Need to add byte-buddy-agent.jar
#oc1bcm55
ByteBuddyAgent.install();
new AgentBuilder.Default()
.type(ElementMatchers.named("com.sakatakoic
hi.logging.Target"))
.transform(new AgentBuilder.Transformer() {
...
})
.installOnByteBuddyAgent();
Without -javaagent
#oc1bcm56
Demo 4
• Add outputting logs without
-javaagent option
#oc1bcm57
Wrap Up
• BM is fun and close to us!
–Many libraries are using
• Application Examples
–Hot Swap
–Advanced Dynamic Proxy
#oc1bcm58

More Related Content

What's hot (20)

PPTX
Lambda Expressions in Java 8
icarter09
 
PDF
Clean Code @Voxxed Days Cluj 2023 - opening Keynote
Victor Rentea
 
PPTX
Fluent validation
Saravanan Subburayal
 
PPTX
Introduction to Spring Boot
Purbarun Chakrabarti
 
PDF
API for Beginners
Sébastien Saunier
 
PDF
A Hands-on Introduction on Terraform Best Concepts and Best Practices
Nebulaworks
 
PDF
Event Driven Systems with Spring Boot, Spring Cloud Streams and Kafka
VMware Tanzu
 
PPTX
Dockers and containers basics
Sourabh Saxena
 
PDF
Spring Boot
HongSeong Jeon
 
PPTX
CA API Gateway: Web API and Application Security
CA Technologies
 
PPTX
What is Docker
Pavel Klimiankou
 
PDF
SSRF vs. Business-critical applications. XXE tunneling in SAP
ERPScan
 
PDF
REST APIs with Spring
Joshua Long
 
PPT
OWASP Top 10 - Experiência e Cases com Auditorias Teste de Invasão em Aplicaç...
Clavis Segurança da Informação
 
PDF
JUnit & Mockito, first steps
Renato Primavera
 
PDF
Burp suite
hamdi_sevben
 
PPTX
Spring Boot and REST API
07.pallav
 
PDF
Credential store using HashiCorp Vault
Mayank Patel
 
PPTX
SOA vs Microservices vs SBA
Michael Sukachev
 
PDF
Making The Move To Java 17 (JConf 2022)
Alex Motley
 
Lambda Expressions in Java 8
icarter09
 
Clean Code @Voxxed Days Cluj 2023 - opening Keynote
Victor Rentea
 
Fluent validation
Saravanan Subburayal
 
Introduction to Spring Boot
Purbarun Chakrabarti
 
API for Beginners
Sébastien Saunier
 
A Hands-on Introduction on Terraform Best Concepts and Best Practices
Nebulaworks
 
Event Driven Systems with Spring Boot, Spring Cloud Streams and Kafka
VMware Tanzu
 
Dockers and containers basics
Sourabh Saxena
 
Spring Boot
HongSeong Jeon
 
CA API Gateway: Web API and Application Security
CA Technologies
 
What is Docker
Pavel Klimiankou
 
SSRF vs. Business-critical applications. XXE tunneling in SAP
ERPScan
 
REST APIs with Spring
Joshua Long
 
OWASP Top 10 - Experiência e Cases com Auditorias Teste de Invasão em Aplicaç...
Clavis Segurança da Informação
 
JUnit & Mockito, first steps
Renato Primavera
 
Burp suite
hamdi_sevben
 
Spring Boot and REST API
07.pallav
 
Credential store using HashiCorp Vault
Mayank Patel
 
SOA vs Microservices vs SBA
Michael Sukachev
 
Making The Move To Java 17 (JConf 2022)
Alex Motley
 

Similar to Bytecode Manipulation with a Java Agent and Byte Buddy (11)

PPTX
Byte code manipulation and instrumentalization in Java
Alex Moskvin
 
PDF
Fun with bytecode weaving
Matthew
 
PPTX
The definitive guide to java agents
Rafael Winterhalter
 
PPTX
Java byte code in practice
Rafael Winterhalter
 
PPTX
Binary patching for fun and profit @ JUG.ru, 25.02.2012
Anton Arhipov
 
PPTX
Bytecode manipulation with Javassist for fun and profit
Jérôme Kehrli
 
PDF
Living in the Matrix with Bytecode Manipulation
C4Media
 
PPTX
Making Java more dynamic: runtime code generation for the JVM
Rafael Winterhalter
 
PDF
Taming Java Agents
Anton Arhipov
 
PDF
Con-FESS 2015 - Having Fun With Javassist
Anton Arhipov
 
PDF
Bytecode manipulation with Javassist and ASM
ashleypuls
 
Byte code manipulation and instrumentalization in Java
Alex Moskvin
 
Fun with bytecode weaving
Matthew
 
The definitive guide to java agents
Rafael Winterhalter
 
Java byte code in practice
Rafael Winterhalter
 
Binary patching for fun and profit @ JUG.ru, 25.02.2012
Anton Arhipov
 
Bytecode manipulation with Javassist for fun and profit
Jérôme Kehrli
 
Living in the Matrix with Bytecode Manipulation
C4Media
 
Making Java more dynamic: runtime code generation for the JVM
Rafael Winterhalter
 
Taming Java Agents
Anton Arhipov
 
Con-FESS 2015 - Having Fun With Javassist
Anton Arhipov
 
Bytecode manipulation with Javassist and ASM
ashleypuls
 
Ad

More from Koichi Sakata (20)

PPTX
Introduction to JIT Compiler in JVM
Koichi Sakata
 
PPTX
Guide to GraalVM (Oracle Groundbreakers APAC 2019 Tour in Tokyo)
Koichi Sakata
 
PPTX
Guide to GraalVM (JJUG CCC 2019 Fall)
Koichi Sakata
 
PPTX
Introduction to GraalVM and Native Image
Koichi Sakata
 
PPTX
Introduction to GraalVM
Koichi Sakata
 
PPTX
GraalVMで使われている、他言語をJVM上に実装する仕組みを学ぼう
Koichi Sakata
 
PPTX
Great Ideas in GraalVM
Koichi Sakata
 
PPTX
Graal in GraalVM - A New JIT Compiler
Koichi Sakata
 
PPTX
Kanjava 201804 Java News
Koichi Sakata
 
PPTX
KanJava 201804 Career 思い込みから逃れた先には、可能性がある
Koichi Sakata
 
PPTX
from Java EE to Jakarta EE
Koichi Sakata
 
PPTX
Java release cadence has been changed and about Project Amber
Koichi Sakata
 
PPTX
JJUG CCC 2017 Fall オレオレJVM言語を作ってみる
Koichi Sakata
 
PPTX
KANJAVA PARTY 2017 前説
Koichi Sakata
 
PPTX
JJUG CCC 2017 Spring Seasar2からSpringへ移行した俺たちのアプリケーションがマイクロサービスアーキテクチャへ歩み始めた
Koichi Sakata
 
PPTX
“Purikura” culture in Japan and our web application architecture
Koichi Sakata
 
PPTX
デブサミ2017 Javaコミュニティ作ったら人生変わった
Koichi Sakata
 
PPTX
JJUG CCC 2016 fall バイトコードが君のトモダチになりたがっている
Koichi Sakata
 
PPTX
日本からJavaOneに行こう!
Koichi Sakata
 
PPTX
Seasar2で作った俺たちのサービスの今
Koichi Sakata
 
Introduction to JIT Compiler in JVM
Koichi Sakata
 
Guide to GraalVM (Oracle Groundbreakers APAC 2019 Tour in Tokyo)
Koichi Sakata
 
Guide to GraalVM (JJUG CCC 2019 Fall)
Koichi Sakata
 
Introduction to GraalVM and Native Image
Koichi Sakata
 
Introduction to GraalVM
Koichi Sakata
 
GraalVMで使われている、他言語をJVM上に実装する仕組みを学ぼう
Koichi Sakata
 
Great Ideas in GraalVM
Koichi Sakata
 
Graal in GraalVM - A New JIT Compiler
Koichi Sakata
 
Kanjava 201804 Java News
Koichi Sakata
 
KanJava 201804 Career 思い込みから逃れた先には、可能性がある
Koichi Sakata
 
from Java EE to Jakarta EE
Koichi Sakata
 
Java release cadence has been changed and about Project Amber
Koichi Sakata
 
JJUG CCC 2017 Fall オレオレJVM言語を作ってみる
Koichi Sakata
 
KANJAVA PARTY 2017 前説
Koichi Sakata
 
JJUG CCC 2017 Spring Seasar2からSpringへ移行した俺たちのアプリケーションがマイクロサービスアーキテクチャへ歩み始めた
Koichi Sakata
 
“Purikura” culture in Japan and our web application architecture
Koichi Sakata
 
デブサミ2017 Javaコミュニティ作ったら人生変わった
Koichi Sakata
 
JJUG CCC 2016 fall バイトコードが君のトモダチになりたがっている
Koichi Sakata
 
日本からJavaOneに行こう!
Koichi Sakata
 
Seasar2で作った俺たちのサービスの今
Koichi Sakata
 
Ad

Recently uploaded (20)

PDF
Newgen 2022-Forrester Newgen TEI_13 05 2022-The-Total-Economic-Impact-Newgen-...
darshakparmar
 
PDF
CIFDAQ Token Spotlight for 9th July 2025
CIFDAQ
 
PDF
Bitcoin for Millennials podcast with Bram, Power Laws of Bitcoin
Stephen Perrenod
 
PDF
POV_ Why Enterprises Need to Find Value in ZERO.pdf
darshakparmar
 
PDF
Smart Trailers 2025 Update with History and Overview
Paul Menig
 
PDF
Newgen Beyond Frankenstein_Build vs Buy_Digital_version.pdf
darshakparmar
 
PDF
CIFDAQ Market Insights for July 7th 2025
CIFDAQ
 
PDF
Mastering Financial Management in Direct Selling
Epixel MLM Software
 
PDF
Building Real-Time Digital Twins with IBM Maximo & ArcGIS Indoors
Safe Software
 
PDF
The 2025 InfraRed Report - Redpoint Ventures
Razin Mustafiz
 
PDF
CIFDAQ Market Wrap for the week of 4th July 2025
CIFDAQ
 
PPTX
MuleSoft MCP Support (Model Context Protocol) and Use Case Demo
shyamraj55
 
PPTX
Mastering ODC + Okta Configuration - Chennai OSUG
HathiMaryA
 
PDF
"AI Transformation: Directions and Challenges", Pavlo Shaternik
Fwdays
 
PDF
Achieving Consistent and Reliable AI Code Generation - Medusa AI
medusaaico
 
PDF
Peak of Data & AI Encore AI-Enhanced Workflows for the Real World
Safe Software
 
PDF
New from BookNet Canada for 2025: BNC BiblioShare - Tech Forum 2025
BookNet Canada
 
PPTX
Webinar: Introduction to LF Energy EVerest
DanBrown980551
 
PDF
“NPU IP Hardware Shaped Through Software and Use-case Analysis,” a Presentati...
Edge AI and Vision Alliance
 
PDF
"Beyond English: Navigating the Challenges of Building a Ukrainian-language R...
Fwdays
 
Newgen 2022-Forrester Newgen TEI_13 05 2022-The-Total-Economic-Impact-Newgen-...
darshakparmar
 
CIFDAQ Token Spotlight for 9th July 2025
CIFDAQ
 
Bitcoin for Millennials podcast with Bram, Power Laws of Bitcoin
Stephen Perrenod
 
POV_ Why Enterprises Need to Find Value in ZERO.pdf
darshakparmar
 
Smart Trailers 2025 Update with History and Overview
Paul Menig
 
Newgen Beyond Frankenstein_Build vs Buy_Digital_version.pdf
darshakparmar
 
CIFDAQ Market Insights for July 7th 2025
CIFDAQ
 
Mastering Financial Management in Direct Selling
Epixel MLM Software
 
Building Real-Time Digital Twins with IBM Maximo & ArcGIS Indoors
Safe Software
 
The 2025 InfraRed Report - Redpoint Ventures
Razin Mustafiz
 
CIFDAQ Market Wrap for the week of 4th July 2025
CIFDAQ
 
MuleSoft MCP Support (Model Context Protocol) and Use Case Demo
shyamraj55
 
Mastering ODC + Okta Configuration - Chennai OSUG
HathiMaryA
 
"AI Transformation: Directions and Challenges", Pavlo Shaternik
Fwdays
 
Achieving Consistent and Reliable AI Code Generation - Medusa AI
medusaaico
 
Peak of Data & AI Encore AI-Enhanced Workflows for the Real World
Safe Software
 
New from BookNet Canada for 2025: BNC BiblioShare - Tech Forum 2025
BookNet Canada
 
Webinar: Introduction to LF Energy EVerest
DanBrown980551
 
“NPU IP Hardware Shaped Through Software and Use-case Analysis,” a Presentati...
Edge AI and Vision Alliance
 
"Beyond English: Navigating the Challenges of Building a Ukrainian-language R...
Fwdays
 

Bytecode Manipulation with a Java Agent and Byte Buddy

Editor's Notes

  • #2: Hello, everyone! Today, I'd like to talk about manipulating Java bytecode. I'll introduce Java Agent and a library called Byte Buddy.
  • #3: Let me briefly introduce myself. I'm Koichi Sakata. I'm a KanJava JUG leader. Kan means Kansai region in Japan. It includes Kyoto. Do you know Kyoto? Kyoto is visited by many tourists. I became a Java champion this year. I work at PONOS Corporation, that is a mobile game company.
  • #4: This session is for beginners, not for experts.
  • #5: Moving on to our main topic. Java bytecode is generated by the javac compiler. It's in a class file. It's an intermediate representation of Java programs. We can visualize bytecode with javap command.
  • #6: What is bytecode manipulation? It's to edit bytecode, such as add, delete and replace bytecode.
  • #7: Why do we manipulate bytecode? Because it's fun!
  • #8: But not only fun. It's also useful to change code at runtime. For example, Hibernate uses bytecode manipulation to generate entity objects, and Mockito uses it to create mock objects. Of course at runtime.
  • #9: It's hard to change bytecode by hand. Because a class file is a binary file and JVM has a verification process for a class file.
  • #10: So there are many libraries for bytecode manipulation. Byte Buddy, Byteman, Javassist, cglib, ASM and BCEL. Today I'll introduce Byte Buddy.
  • #11: Why Byte Buddy? Byte Buddy has a Easy-to-use API, supports Java 11 already and won a Duke's Choice Award.
  • #12: Many major libraries are using Byte Buddy, such as Hibernate, Mockito, Jackson, etc.
  • #13: This is a hello world program with Byte Buddy. It creates a new class that extends Object class, and overrides toString() method to return "Hello World". I'll explain the details of this code.
  • #14: First, we create a subclass of the Object class and choose the toString() method.
  • #15: Next, we intercept the metod to return a fixed string value "Hello World".
  • #16: Make method builds a new type. The new type isn't loaded by a classloader yet, so the type is an unloaded class. Then the classloader loads the type. Finally we can get the new loaded class object. It's easy to manipulate bytecode with Byte Buddy. That's the reason why Byte Buddy is so popular.
  • #17: OK, I explained all parts of this code.
  • #18: Let's run the hello world. This code is a bit different from the previous code. I'll save a generated class to a file and outputs the method return. (run HelloWorld) Let's see the generated file. It is in a temp directory. Byte Buddy names the dynamic class randomly.
  • #19: By the way, the demo code used today is available on GitHub. Just access "bitly/oc1bcm"
  • #20: Now I'd like to show code in Mockito. Mockito is a famous mocking framework. This method creates a mock class. As you can see, it's similar to our hello world example.
  • #21: How to use? You can run bytecode manipulation code directly in your application. But you need to change your code. When you choose the second option, you need to rebuild. So I'd like to introduce Java Agent. It doesn't require the change. It's also detachable.
  • #22: What is Java Agent? The word "Agent" invokes the "Mission: Impossible" spy series. Java Agent do espionage activities in your application, like profiling, logging and even changing the behavior of the application itself.
  • #23: Java Agent can instrument programs running on the JVM. It's defined as JSR 163. The JVM calls Java Agent methods with proper timing.
  • #24: To create a Java Agent, just define one of the these methods or both, premain() and agentmain().
  • #25: Premain() method is called by the JVM before the application's main method(). Agentmain() is called when the agent is attached after the JVM has started.
  • #26: So with Java Agent, we can run bytecode manipulation code at runtime.
  • #27: To create a Java Agent, first, define the Agent Class method. Second, write a MANIFEST.MF file. Third, package the Agent class to a JAR file. Finally, run java command with javaagent option.
  • #28: A signature of premain() is "public static void premain()". We can have an opportunity to modify classes before the class is loaded. Instrumentation class in method parameters provides useful methods to modify classes.
  • #29: In the manifest file, we specify the Agent class and set the path to the Byte Buddy's JAR file.
  • #30: Let's create a simple Java Agent. The Agent class is a Java agent class. It has the premain() method. This is the Main class. Run the main() method with javaagent option. As you can see, premain() executed before main method.
  • #31: Let's combine Java Agent with Byte Buddy. I'll show another example. It adds outputting logs before executing a particular method on a particular class.
  • #32: I'll do two things. First, define the premain() method in a class. Second, write code in premain() method to replace the class file to output a log. Note that I don't create a subclass.
  • #33: This is the Target class. We want to output a log when foo() method is called.
  • #34: Next, replace the class with Byte Buddy. Let me explain the details of this code.
  • #35: This code uses rebase() method, instead of previous subclass() method. Rebase() method doesn't create a subclass. It replaces the original implementation with new one and saves it under a different method name.
  • #36: Byte Buddy provides three method to enhance existing methods. Subclass() creates a subclass and overrides the method. Redefine() replaces the implementation with new one. Rebase() also replaces it and saves the original implementation.
  • #37: Note that we can't use a class literal. If we use a class literal for the Target class, the JVM will load the class before changing the class. We can use the TypePool class and its describe() method, to represent the class without the class literal.
  • #38: Also, note that when using unloaded classes, we need to specify a ClassFileLocator. It allows to locate a class file. In this example, we simply create a class file locator with ofClassPath() method. It scans the running application's class path for class files.
  • #39: This time I'd like to delegate outputting to another class, LoggingInterceptor class.
  • #40: To do so, We can use MethodDelegation.to() method. We simply specify a class to delegate. A best match method is chosen automatically by Byte Buddy.
  • #41: After the method is invoked, the original call will continue, thanks to andThen() method with SuperMethodCall.INSTANCE. SuperMethodCall.INSTANCE represents the original method.
  • #42: This is the interceptor class. This code outputs the intecepted method name.
  • #43: In delegated method, various annotations can be used. The Origin annotation is a reference to the original method or constructor. So we can get the method object of the original method.
  • #44: Other annotations are shown here. More details can be found in the Byte Buddy's website.
  • #45: Go back to the premain(). How do we run that code in Java Agent? Instrument API provides ClassFileTransformer class to change bytecode. To manipulate bytecode in Java Agent, We need to override transform(). Then pass the ClassFileTransformer instance to addTransformer() of the Instrumentation class. The transform() will be called by the JVM before loading.
  • #46: Let's go on to the transform() method. We can call the manipulation code in transform() method.
  • #47: In parameters, class name is the name to be loaded. Class file buffer is the content of the class file.
  • #48: We return the class file content from the transform().
  • #49: Finally we can run the demo. Let's see the complete code. (Show LoggingAgent class) (run Target class) OK, foo() is intercepted.
  • #50: So we covered the basics of Byte Buddy and Java Agent.
  • #51: Of course, there are many features in Byte Buddy. Add fields and methods, manipulate even stacks. Also, we can generate CONDY code with Byte Buddy. Have you ever heard about condy? CONDY means constant dynamic. It defines as JEP 309. It's included from Java 11, but the Java compiler doesn't use CONDY yet. We can try to use CONDY directly with Byte Buddy.
  • #52: Acutually Byte Buddy provides AgentBuilder class to simplify Java Agent. We can rewrite the previous Logging Agent with AgentBuilder.
  • #53: Just use AgentBuilder class instead of ByteBuddy class, and use AgentBuilder.Transformer instead of ClassFileTransformer. Call install() method at the end.
  • #54: Use AgentBuilder, Use AgentBuilder.Transformer and call installOn().
  • #55: Then We can use builder object to intercept the method. Let's see the complete code. (show LoggingAgent class) This code is more readable, isn't it? (mvn package & run Target class)
  • #56: Additionally, when we use AgentBuilder, we can remove javaagent option. Just call ByteBuddyAgent's install() and AgentBuilder's installOnByteBuddyAgent() instead of installOn() method. To use ByteBuddyAgent, we need to add byte-buddy-agent JAR file to the class path.
  • #57: Call ByteBuddyAgent.install() and AgentBuidler's installOnByteBuddyAgent().
  • #58: (show LoggingMainWithoutAgent class) Run this code without javaagent option. (run LoggingMainWithoutAgent)
  • #59: Let's wrap up. Bytecode manipulation is fun, and it's close to us. I'd like to stress this point. Many famous libraries are using bytecode manipulation. As application examples, there are How Swap, which swap classes at runtime, and advanced dynamic proxy.