【问题标题】:Why does ByteBuddy route method delegation to the "wrong" method in this scenario?在这种情况下,为什么 ByteBuddy 将方法委托路由到“错误”的方法?
【发布时间】:2020-03-23 21:09:09
【问题描述】:

我正在整理一个非常简单的 ByteBuddy 委托/代理类。

目的是(再次,非常简单)代理一个类,使其任何非final、非private、非static 方法等都被路由到其@ 上的等效方法987654324@ 字段由其getProxiedInstance 方法返回。 (对于常见的嫌疑人应该有例外:equalshashCodewaitnotify等等。)

我已经使用子类策略设置了我的代理类。我还定义了两个方法,getProxiedInstancesetProxiedInstance,以及一个名为proxiedInstance 的正确类型的private 字段。我已经使用FieldAccessor.ofBeanProperty() 策略完成了这项工作。为了简洁和清楚起见,我在这里省略了它。该类实际上包含该字段和这两个方法。

然后我这样定义方法拦截,静态导入相关的ElementMatchers方法:

builder
      .method(not(isFinal()).and(not(isStatic())).and(not(isPrivate()))
              .and((isPublic().and(named("toString")).and(takesArguments(0)).and(returns(String.class)))
                   .or((not(isDeclaredBy(Object.class)).and(not(named("getProxiedInstance"))).and(not(named("setProxiedInstance"))))))
              )
      .intercept(MethodDelegation.toMethodReturnOf("getProxiedInstance"));

英文:not final,not static,not private或者public String toString()方法继承自Object(或被覆盖),或 任何其他未由 Object.class 声明且未命名为 getProxiedInstancesetProxiedInstance 的方法。

假设我有这样的课程:

public class Frob {

  public String sayHello() {
    return "Hello!";
  }

}

当我为它创建一个代理类,实例化它,然后在代理上调用toString(),我得到Hello!

这以某种方式向我暗示,我上面引用的配方以某种方式将toString() 路由到sayHello()

通过阅读MethodDelegation javadocs,似乎可能选择目标/委托对象上的sayHello 进行委托,因为它比代理上调用的方法 (toString) 更具体。我猜名字匹配的优先级低于那个。

我认为我的这个用例比较简单。我怎样才能最好地完成它?

【问题讨论】:

    标签: byte-buddy


    【解决方案1】:

    我能做的最好的事情是这样的:

    builder = builder
          .method(not(isDeclaredBy(Object.class))
                  .and(not(isFinal()))
                  .and(not(isStatic()))
                  .and(not(isPrivate()))
                  .and(not(named("getProxiedInstance")))
                  .and(not(named("setProxiedInstance"))))
          .intercept(MethodDelegation.toMethodReturnOf("getProxiedInstance"))
          .method(is(toStringMethod))
          .intercept(invoke(toStringMethod).onMethodCall(invoke(named("getProxiedInstance"))));
    

    toStringMethod 是由Object.class.getMethod("toString") 产生的Method。)

    【讨论】:

      【解决方案2】:

      我认为使用MethodCall 是一种更好的方法。 MethodDelegation 用于“捕获所有代理”,您可以将相应的调度程序注入到通常是单个委托方法(可能是两个)中。方法调用的性能也更高,因为它不需要进行分析,只需重新路由到兼容类型的方法。

      【讨论】:

      • 感谢您的回答。我的理解是MethodCall,但是,我必须知道要调用什么方法。是否有一些我不知道的使用流利 API 的配方,“如果用户调用 x,则在 proxiedInstance 上调用 x”?
      • 换句话说:我不知道用户将在动态类型上调用什么方法。当她调用该方法时,无论它是什么,我都想在getProxiedInstance 的返回值上调用一个等效方法。 MethodCall.invoke(ElementMatcher) 似乎适用于 instrumented 类型,我没有看到与“用户最初调用的任何内容”匹配的 ElementMatcher
      • MethodCall 就是这样做的。例如,在字段上调用调用的方法。
      • 好的;我应该从哪个静态MethodCall 方法开始?对不起,我这么笨!
      • 我试着在这里做功课; github.com/raphw/byte-buddy/blob/master/byte-buddy-dep/src/test/… 虽然只显示了预先知道invoke 的参数的用法。那不是我的情况。
      猜你喜欢
      • 1970-01-01
      • 2018-06-24
      • 1970-01-01
      • 1970-01-01
      • 2012-08-27
      • 2018-04-10
      • 2014-10-26
      • 1970-01-01
      • 2011-03-26
      相关资源
      最近更新 更多