I am trying to manipulate a static method. For this, Byte Buddy or any other framework can be used.
There is one library that is called Pi4J that is used for controlling GPIO of Raspberry Pi. This library has a method called:
GpioController gpio = GpioFactory.getInstance();
And this call is called in several places of a program that I might not have control such that I need to modify the invocation.
What I would like to do is that when GpioFactory.getInstance
is executed in some way detect and modify the methods of GpioController
so they log that they have been called.
Maybe the only solution is by using AspectJ, but do you know if Byte Buddy could be a solution?
The code for Pi4J is open source on github under LGPL license. You can simply clone the repository, modify to your needs and use own version. If you feel your changes can help others as well think about contributing tp pi4j.
This is perfectly possible when using a Java agent in combination with Byte Buddy. For example, you can modify the GpioFactory::getInstance
method as demonstrated by the following Java agent:
public class MyAgent {
public static void premain(String arg, Instrumentation inst) {
new AgentBuilder.Default()
.type(ElementMatchers.named("com.pi4j.io.gpio.GpioFactory")
.transform((builder, type) -> // Or anonymous class for pre Java 8
builder.method(ElementMatchers.named("getInstance"))
.intercept(MethodDelegation.to(MyFactory.class));
).installOn(inst)
}
}
public class MyFactory {
public static GpioController intercept(@SuperCall Callable<GpioController> s)
throws Exception {
return s.call(); // Wrap controller here.
}
}
Using this agent, Any controller instance that is returned from the original getInstance
method would be passed through the MyFactory::intercept
method.
Alternatively, you can equally instrument all implementations of GpioController
to directly do the logging. This would then affect all instances of the interface.
If you do not have the possibility to add a Java agent at startup, on JDKs (not standard JVMs), you can use ByteBuddyAgent.install()
(from the byte-buddy-agent
dependency) to manually install an agent at runtime. In this case, you need to make sure however that the agent is installed before the GpioFactory
is loaded. You can find more information in the documentation of the library.
Finally, note that AspectJ and Byte Buddy both use a Java agent to achieve their instrumentation. AspectJ does however use its own syntax where Byte Buddy models its API in Java what is the main core difference.