【问题标题】:ByteBuddy - Modify load class's default valueByteBuddy - 修改加载类的默认值
【发布时间】:2016-05-06 03:26:40
【问题描述】:

我正在尝试更改已加载类的方法的返回值。

从 ByteBuddy 的文档 (http://bytebuddy.net/#/tutorial) 来看,这似乎可以使用 Java 代理,只要我不添加任何字段/方法。

我的代码如下:

ByteBuddyAgent.install();

new ByteBuddy()
        .redefine(StuffImpl.class)
        .method(returns(Result.class))
        .intercept(FixedValue.value(new Result("intercepted")))
        .make()
        .load(StuffImpl.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());

但我得到以下异常:

java.lang.UnsupportedOperationException: class redefinition failed: attempted to change the schema (add/remove fields)

问题是,我没有添加任何方法。上面代码中Byte Buddy在哪里添加了字段或方法?

编辑:

public class StuffImpl {

    public Result validate() {
        return new Result("original");
    }
}

public class Result {

    private String result;

    public Result(String result) {
        this.result = result;
    }
}

【问题讨论】:

    标签: java bytecode byte-buddy


    【解决方案1】:

    您为字节好友需要存储在某处的固定值new Result("intercepted") 定义一个委托。 FixedValue 实现为您创建一个静态字段,以便生成的方法可以从中读取您的值。您可以通过避免FixedValue 以不同方式解决此问题,例如:

    1. 委托给另一个在字段中保存值的类(保留引用标识)。

      MethodDelegation.to(Holder.class);
      class Holder {
        static Result result = new Result("intercepted");
        static Result intercept() { return result; }
      }
      

      这是最通用的方法,当然可以直接从方法中返回new Result("intercepted")

    2. 动态创建实例:

      MethodCall.construct(Result.class.getDeclaredConstructor(String.class))
                .with("intercepted");
      

      在这种情况下,"intercepted" 字符串不需要存储在字段中,因为它可以在类的常量池中被引用(原始值也是如此)。


    你的StuffImpl 可能定义了一个静态初始化器。这个初始化器被 Byte Buddy 分解成一个 private 方法,这样它就可以向它添加额外的语句。

    您可以通过设置禁用此行为:

    new ByteBuddy().with(Implementation.Context.Disabled.Factory.INSTANCE);
    

    这确实应该在文档中,我将在下一个版本中添加它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多