2016-01-28 113 views
2

我試圖改變一個已經加載類的方法的返回值。ByteBuddy - 修改加載類的默認值

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

回答

2

你定義一個代表團到一個固定值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); 

這確實應該在文檔中,我將它添加下一個版本。