2016-01-28 8 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 добавляет поле или метод в вышеуказанный код?

EDIT:

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"), что Byte Buddy должен хранить где-то. Реализация FixedValue создает для вас статическое поле, так что сгенерированный метод может считывать ваше значение из него. Вы можете работать Arround это по-разному, избегая 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); 

Это должно быть действительно в документации, и я добавлю его в следующем выпуске.

 Смежные вопросы

  • Нет связанных вопросов^_^