使用@Super在bytebuddy中委托私有方法 - 可能吗?

时间:2016-10-11 21:56:22

标签: java reflection byte-buddy

我正在尝试在bytebuddy中委托一个私有方法 - 但是如何调用'overriden'版本?如果我有

    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());

public class Foo
{
    private int num = 0;

    public String getMessage()
    {
        return "Message is Foo " + getNum();
    }
    private int getNum()
    {
        return num++;
    }
}

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;
    }
}

就编译器而言,即使@Super Foo foo在运行时变为其他东西,我也不允许在Foo上调用私有方法。我似乎也无法反映/调用getNum() - 无论@Super Foo变为什么,它似乎都没有getNum()方法(尽管它有{{1} }} 方法)。

有人可能会指出我在正确的方向吗?

更新

@Rafael的回答在技术上是我提出的问题的一个非常好的解决方案;不幸的是,我猜我的榜样很糟糕。 Mea culpa。我真正希望的是一个解决方案,让我在传递它们之前操纵getMessage()的参数。但事实证明,对于我的应用程序,我可能无需这样做,所以如果这发生了变化,那么也许我会发布那个确切的例子。

更新2:

问题完全回答了!欢呼!

1 个答案:

答案 0 :(得分:2)

您可能想要使用@SuperCall Callable。这将允许您从方法本身调用重写的方法。但它不允许您从代理类中调用任何方法。

public class FooInterceptor
{
  public static int getNum(@SuperCall Callable<Integer> c) throws Exception
  {
    // This will work!
    return c.call() + 100;
  }
}

如果需要操作参数,可以使用Morph注释。它允许您在提供显式参数的同时调用方法:

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;
  }
}

请注意,您需要明确安装接口:

MethodDelegation.to(FooInterceptor.class)
   .appendParameterBinder(Morph.Binder.install(Morphing.class));