Reputation: 627
I have a class which looks like below
public class HelloWorld{
public void sayHelloWorld(){
System.out.println("Hello World");
}
}
Now I would like to add another method to the HelloWorld class using bytebuddy and add a call to the new method in sayHelloWorld. So hypothetically the class would look like this after bytebuddy does it's magic. (I know that bytebuddy works with bytecode and not java source files. The below code is just for illustration purpose.)
public class HelloWorld{
public void sayHelloWorld(){
System.out.println("Hello World");
sayHelloAgain()
}
public void sayHelloAgain(){
System.out.println("Hello Again")
}
}
It would be great if someone could shed some light on this. TIA!
Upvotes: 3
Views: 3833
Reputation: 44032
Byte Buddy allows you to do this in various ways. The most straight forward way would be to define an interceptor that implements sayHelloAgain
to which Byte Buddy creates a delegation:
public class HelloAgainDelegate {
public static void sayHelloAgain() {
System.out.println("Hello again");
}
}
You can then define the method on the redefined class and rebase the sayHelloWorld
method to first invoke the original method and then invoke the other method:
Class<?> type = new ByteBuddy()
.rebase(HelloWorld.class)
.defineMethod("sayHelloAgain", void.class, Visibility.PUBLIC)
.intercept(MethodDelegation.to(HelloAgainDelegate.class))
.method(named("sayHelloWorld"))
.intercept(SuperMethodCall.INSTANCE
.andThen(MethodCall.invoke(named("sayHelloAgain"))))
.make()
.load(HelloWorld.class.getClassLoader(),
ClassLoadingStrategy.Default.CHILD_FIRST)
.getLoaded();
Object instance = type.newInstance();
type.getMethod("sayHelloWorld").invoke(instance);
type.getMethod("sayHelloAgain").invoke(instance);
In Java code, the rebased class would look something like this:
public class HelloWorld {
synthetic void sayHelloWorld$origin() {
System.out.println("Hello World");
}
public void sayHelloWorld() {
sayHelloWorld$origin();
sayHelloAgain();
}
public void sayHelloAgain() {
HelloAgainInterceptor.sayHelloAgain();
}
}
If this delegation is not an option for you, you can also use Advice
to inline the code from a template class:
class HelloAgainAdvice {
@Advice.OnMethodExit
static void sayHelloAgain() {
System.out.println("Hello again");
}
}
Instead of the MethodDelegation
, you would use this class via Advice.to(HelloAgainAdvice.class)
. As the code is copied, you will not be able to set break points but your redefined class will be self-contained.
Upvotes: 6