我试图更改已加载类的方法的返回值。
来自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;
}
}
答案 0 :(得分:2)
您将委托定义为Byte Buddy需要存储在某处的固定值new Result("intercepted")
。 FixedValue
实现为您创建一个静态字段,以便生成的方法可以从中读取您的值。您可以通过避免FixedValue
以不同方式解决此问题,例如:
委托另一个在字段中保存值的类(保留引用标识)。
MethodDelegation.to(Holder.class);
class Holder {
static Result result = new Result("intercepted");
static Result intercept() { return result; }
}
这是最通用的方法,您当然可以直接从方法返回new Result("intercepted")
。
动态创建实例:
MethodCall.construct(Result.class.getDeclaredConstructor(String.class))
.with("intercepted");
在这种情况下,"intercepted"
字符串不需要存储在字段中,因为它可以在类的常量池中引用(对于原始值也是如此)。
您的 StuffImpl
可能定义了静态初始值设定项。 Byte Buddy将此初始化程序分解为private
方法,以便它可以向其添加其他语句。
您可以通过设置:
来禁用此行为new ByteBuddy().with(Implementation.Context.Disabled.Factory.INSTANCE);
这应该在文档中,我将在下一个版本中添加它。