I am trying to redefine 2 methods using ByteBuddy, like so:
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
ClassLoadingStrategy.Default classLoadingStrategy = ClassLoadingStrategy.Default.INJECTION;
new ByteBuddy().redefine(CommandBase.class).method(returns(Item.class)).intercept(MethodDelegation.to(CppItemInterceptor.class)).make().load(classLoader, classLoadingStrategy);
new ByteBuddy().redefine(CommandBase.class).method(returns(Block.class)).intercept(MethodDelegation.to(CppBlockInterceptor.class)).make().load(classLoader, classLoadingStrategy);
try {
System.out.println(CppBlockInterceptor.getBlockByText(null, "1").getLocalizedName());
System.out.println(CommandBase.getBlockByText(null, "1").getLocalizedName());
} catch (Exception e) {
e.printStackTrace();
}
The direct call to CppBlockInterceptor produces the intended output, but the call to the method that was supposed to be replaced still uses the old behavior. Is there any reason for this?
Your CommandBase
class is already loaded before you get the chance to redefine it. Byte Buddy cannot replace a loaded class without using a Java agent. Try running this:
TypeDescription commandBase = new TypePool.Default.ofClassPath()
.locate("my.package.CommandBase");
new ByteBuddy()
.redefine(commandBase, ClassFileLocator.ForClassLoader.ofClassPath())
.method(returns(Block.class)).intercept(MethodDelegation.to(CppBlockInterceptor.class))
.make()
.load(ClassLoader.getSystemClassLoader(), ClassLoadingStrategy.Default.INJECTOR);
CppBlockInterceptor.getBlockByText(null, "1").getLocalizedName()
without explicitly referrencing CommandBase
before the invocation and it will work. Better would be to use an AgentBuilder
and a Java agent, though. The documentation of Byte Buddy explains why.