Метод делегирования на поле и приведение в Bytebuddy - PullRequest
1 голос
/ 09 июля 2020

Использование Bytebuddy предполагает следующее:

class Service {
    protected Handler handler;
...
}

interface Handler {
   public void handle();
}

class ConcreteHandler implements Handler {
    public void handle() {
       ...
    }
    public void handle2() {
       ...
    }
}

Обычно мы вызываем метод handle () Handler, но в некоторых случаях нам нужно вызвать handle2 () класса ConcreteHandler, который находится во время выполнения. Теперь вопрос: возможно ли это с помощью Bytebuddy? Возможно, да, но как?

Я пробовал это:

if (condition) {
    MethodCall methodCall = (MethodCall) 
        MethodCall.invoke(methodHandle2).onField("handler")
                        .withAssigner(Assigner.DEFAULT, Assigner.Typing.DYNAMIC);
}

... но это не удается с исключением IllegalStateException: невозможно вызвать publi c void com.framework.ConcreteHandler.handle2 ( ...) на защищенном com.framework.Handler com.framework.Service.handler

Есть идеи?

Ответы [ 2 ]

2 голосов
/ 11 июля 2020

Кажется, это ошибка в Byte Buddy. Я надеюсь, что исправил проблему в этой фиксации , которая должна решить проблему в Byte Buddy 1.10.14. А пока вы можете попробовать сделать снимок.

1 голос
/ 09 июля 2020

Если ваша переменная поля - Handler, вы не можете вызвать handle2(), так как обработчик не знает о методе handle2().

Чтобы вызвать метод handle2() (для допустимый класс), вам нужно преобразовать handler в ConcreteHandler - процесс, известный как «понижающее преобразование», когда вы приводите экземпляр к объекту, находящемуся ниже в иерархии объектов. Это работает только тогда, когда экземпляр handler на самом деле является ConcreteHandler, а не каким-либо другим производным от Handler.

, пример:

if (handler instanceof ConcreteHandler) {
   ConcreteHandler concreteHandler = (ConcreteHandler) handler;
   concreteHandler.handle2();
}

EDIT: одноразовое перенаправление Я получил работу. Я не совсем уверен, как вы можете заставить его работать как постоянное перенаправление из документации, но, похоже, переопределение сработает, если вы хотите перенаправить метод навсегда. Также было внесено изменение в исходный код, необходимый для создания классов ConcreteHandler, Handler, et c, publi c.

 new ByteBuddy()
                .subclass(ConcreteHandler.class)
                .method(named("handle")).intercept(MethodDelegation.to(ConcreteHandler.class))
                .make()
                .load(getClass().getClassLoader())
                .getLoaded()
                .newInstance()
                .handle2();
...