I'm trying to delegate a private method in bytebuddy - but how do I call the 'overriden' version? If I have
TypePool typepool = TypePool.Default.ofClassPath();
new ByteBuddy()
.rebase(typepool.describe("Foo").resolve(), ClassFileLocator.ForClassLoader.ofClassPath())
.method(named("getNum"))
.intercept(MethodDelegation.to(typepool.describe("FooInterceptor").resolve()))
.make()
.load(typepool.describe("Foo").resolve().getClass().getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
Foo foo1 = new Foo();
System.out.println("Foo says " + foo1.getMessage());
and
public class Foo
{
private int num = 0;
public String getMessage()
{
return "Message is Foo " + getNum();
}
private int getNum()
{
return num++;
}
}
and
import net.bytebuddy.implementation.bind.annotation.Super;
public class FooInterceptor
{
public static int getNum(@Super Foo foo)
{
// This won't work!
return foo.getNum() + 100;
}
}
As far as the compiler is concerned, even if @Super Foo foo
is going to become something else at runtime, I'm not allowed to call a private method on Foo. I don't seem to be able to reflect/invoke getNum()
either - whatever @Super Foo
becomes, it doesn't seem to have a getNum()
method (although it does have a getMessage()
method).
Can someone perhaps point me in the right direction here?
Update:
@Rafael's answer is technically a very good solution to the question I asked; unfortunately I guess my example was bad. Mea culpa. What I was really hoping for was a solution that would let me manipulate the arguments to getNum()
before passing them. But it turns out that for my application I might be able to get by without doing that, so if that changes then perhaps I'll post that exact example.
Update 2:
Question completely answered! Hurray!
You probably want to use @SuperCall Callable
. This would allow you to do invoke the overridden method from the method itself. It does however not allow you to invoke any method from within a proxied class.
public class FooInterceptor
{
public static int getNum(@SuperCall Callable<Integer> c) throws Exception
{
// This will work!
return c.call() + 100;
}
}
If you need to manipulate the arguments, this is possible by using the Morph
annotation. It allows you to invoke a method whilst supplying explicit arguments:
public interface Morphing<T> {
T invoke(Object[] args);
}
public class FooInterceptor
{
public static int getNum(@Morph Morphing<Integer> m, @AllArguments Object[] args)
{
// This will work!
return m.invoke(args) + 100;
}
}
Note that you need to install the interface explicitly:
MethodDelegation.to(FooInterceptor.class)
.appendParameterBinder(Morph.Binder.install(Morphing.class));
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.