java - 如何使用 MethodDelegation 或 Forwarding 创建 Byte Buddy 代理?

标签 java byte-buddy

当我尝试执行以下操作时,加载调用出现异常:

  Field datasourceExtensionField = Grid.class.getDeclaredField("datasourceExtension");
  datasourceExtensionField.setAccessible(true);
  RpcDataProviderExtension rpcDataProviderExtension = (RpcDataProviderExtension) datasourceExtensionField.get(grid);

  Field activeItemHandlerField = RpcDataProviderExtension.class.getDeclaredField("activeItemHandler");
  activeItemHandlerField.setAccessible(true);
  Object activeItemHandler = activeItemHandlerField.get(rpcDataProviderExtension);

  Field keyMapperField = activeItemHandler.getClass().getDeclaredField("keyMapper");
  keyMapperField.setAccessible(true);
  KeyMapper original = (KeyMapper) keyMapperField.get(activeItemHandler);

  KeyMapper wrapper = new ByteBuddy() //
      .subclass(KeyMapper.class) //
      .defineField("original", KeyMapper.class, Visibility.PUBLIC) //
      .method(ElementMatchers.any()) //
      .intercept(Forwarding.toField("original")) //
      .method(ElementMatchers.named("get")) //
      .intercept(MethodDelegation.to(new KeyMapperWrapper(grid, original))) //
      .make() //
      .load(KeyMapperWrapper.class.getClassLoader()) //
      .getLoaded() //
      .newInstance();

  // give wrapper the reference to the original
  wrapper.getClass().getDeclaredField("original").set(wrapper, original);

  // replace original with wrapper
  keyMapperField.set(activeItemHandler, wrapper);

异常:

java.lang.VerifyError: Bad access to protected data in invokevirtual
Exception Details:
  Location:
    com/vaadin/server/KeyMapper$ByteBuddy$WlWljaQa.clone()Ljava/lang/Object; @4: invokevirtual
  Reason:
    Type 'com/vaadin/server/KeyMapper' (current frame, stack[0]) is not assignable to 'com/vaadin/server/KeyMapper$ByteBuddy$WlWljaQa'
  Current Frame:
    bci: @4
    flags: { }
    locals: { 'com/vaadin/server/KeyMapper$ByteBuddy$WlWljaQa' }
    stack: { 'com/vaadin/server/KeyMapper' }
  Bytecode:
    0x0000000: 2ab4 000c b600 1cb0                    

    at java.lang.Class.getDeclaredFields0(Native Method)
    at java.lang.Class.privateGetDeclaredFields(Class.java:2583)
    at java.lang.Class.getDeclaredField(Class.java:2068)
    at net.bytebuddy.implementation.LoadedTypeInitializer$ForStaticField.onLoad(LoadedTypeInitializer.java:101)
    at net.bytebuddy.implementation.LoadedTypeInitializer$Compound.onLoad(LoadedTypeInitializer.java:180)
    at net.bytebuddy.dynamic.TypeResolutionStrategy$Passive.initialize(TypeResolutionStrategy.java:75)
    at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:4525)
    at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:4514)
    at test.KeyMapperWrapper.patch(KeyMapperWrapper.java:62)

我显然不明白 Forwarding 应该如何工作,我做错了什么?

我的意图是用一个代理替换现有的 KeyMapper,在代理中我覆盖一个方法,并将其余方法委托(delegate)给原始方法。

编辑:我现在也尝试使用 MethodDelegation,它会引发相同的异常:

 .method(ElementMatchers.any()) //
 .intercept(MethodDelegation.to(original)) //
 .method(ElementMatchers.named("get")) //
 .intercept(MethodDelegation.to(new KeyMapperWrapper(grid, original))) //

最佳答案

这是字节好友中的一个错误。但是,您尝试创建的类型不合法,Byte Buddy 无法为您提供正确的错误消息。子类化时,覆盖 protected 方法是合法的。然而,由于可见性限制,在另一种类型上调用这些方法并不总是合法的。因此,当您转接调用时,您只能覆盖 public 方法。你要做的是匹配:

.method(ElementMatchers.isPublic())

错误不再发生的地方。我已经在 Byte Buddy 的下一个发行版本 (1.5.8) 中添加了一个修复程序来为您提供此错误消息。

关于java - 如何使用 MethodDelegation 或 Forwarding 创建 Byte Buddy 代理?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40962305/

相关文章:

java - 在委托(delegate)另一个包中的接口(interface)的方法时,如何使委托(delegate)类成为非公开的?

java - Hibernate 中使用 ByteBuddy 代理的 MethodHandler 陷入无限循环

java - 在 OpenGL ES 2.0 中使用多个纹理

java - 在以下情况下最终会发生什么阻塞?

java - PhotoView 库和图像设置为壁纸

java - 不可修改的堆栈

java - 如何克隆对象以移动某些内容并查看移动是否有效? ( java 、国际象棋)

java - 如果代理类具有包私有(private)默认构造函数,则代理实例化失败

java - 使用 ByteBuddy 装饰 ClassLoader 方法

byte-buddy - 用于构建上限通配符的 ByteBuddy 配方是什么?