简体   繁体   中英

Delegate private method in bytebuddy with @Super - possible?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM