Украсьте метод с помощью ByteBuddy

Как я могу определить метод, а затем украсить его (несколько раз) с помощью ByteBuddy? это мой пример

Builder<Object> builder = new ByteBuddy().subclass(Object.class).name("Dynamic");
    builder = builder.defineMethod("method", void.class, Visibility.PUBLIC)
    .intercept(MethodDelegation.to(new Object(){
        
        @RuntimeType
        public void intercept(@This Object o) {
            System.out.println("Executing code...");
        }
        
    }));
    
    builder = builder.method(ElementMatchers.named("method")).
    intercept(MethodDelegation.to(new Object(){
        
        @RuntimeType
        public void intercept(@This Object o) {
            System.out.println("Executing other code...");
        }
        
    }));
    
    try {
        Class cls = builder.make()
                .load(StructClassBuilder.class.getClassLoader())
                .getLoaded();
        
        Object obj = cls.newInstance();
        cls.getDeclaredMethod("method").invoke(obj, args);
    } catch (Exception e1) {
        e1.printStackTrace();
    }

Выход

Выполнение другого кода...

Я хотел бы, чтобы выход был

Выполнение кода...

Выполнение другого кода...

Спасибо


person Marpa    schedule 03.11.2017    source источник


Ответы (2)


Один из вариантов - связать ваши перехватчики с помощью методов MethodDelegation.to(...).addThen(...).

public class ByteBuddyTest {

  public static void main(String[] args) throws Exception {
    DynamicType.Builder<Object> builder = new ByteBuddy().subclass(Object.class).name("Dynamic");
    builder = builder
        .defineMethod("method", void.class, Visibility.PUBLIC)
        .intercept(MethodDelegation.to(Interceptor1.class).andThen(MethodDelegation.to(Interceptor2.class)));

    try {
        Class<?> clazz = builder.make().include().load(ByteBuddyTest.class.getClassLoader()).getLoaded();

        Object obj = clazz.newInstance();
        clazz.getDeclaredMethod("method").invoke(obj, args);
    } catch (Exception e1) {
        e1.printStackTrace();
    }
  }

  public static class Interceptor1 {

      public static void intercept() {
          System.out.println("Executing code...");
      }
  }

  public static class Interceptor2 {

      public static void intercept() {
          System.out.println("Executing other code...");
      }
  }
}
person kaos    schedule 03.11.2017
comment
У меня есть ограничение, я не могу создавать подклассы несколько раз. Я буду использовать шаблон декоратора, чтобы украсить Interceptor. Спасибо. - person Marpa; 03.11.2017
comment
Я понимаю. Я обновил свой ответ альтернативным решением вашего ответа. - person kaos; 03.11.2017

Я буду использовать шаблон декоратора для украшения перехватчика, теперь он работает как положено. Делюсь своим решением:

private static interface Interceptor{
    public void intercept(@This Object o);
}

private abstract static class InterceptorDecorator implements Interceptor{

    protected Interceptor interceptor;

    public InterceptorDecorator(Interceptor interceptor){
        this.interceptor = interceptor;
    }

    public void intercept(@This Object o) {
        if(interceptor!=null){
            interceptor.intercept(o);       
        }
    }

}

private static class Interceptor1 extends InterceptorDecorator{

    public Interceptor1(Interceptor interceptor) {
        super(interceptor);
    }

    public void intercept(@This Object o) {
        super.intercept(o);
        System.out.println("Executing code...");            
    }

}

private static class Interceptor2 extends InterceptorDecorator{

    public Interceptor2(Interceptor interceptor) {
        super(interceptor);
    }

    public void intercept(@This Object o) {
        super.intercept(o);
        System.out.println("Executing other code...");          
    }

}

public static void main(String[] args) {

    Interceptor interceptor = new Interceptor1(null);
    interceptor = new Interceptor2(interceptor);

    Builder<Object> builder = new ByteBuddy().subclass(Object.class).name("Dynamic");
    builder = builder.defineMethod("method", void.class, Visibility.PUBLIC)
    .intercept(MethodDelegation.to(interceptor));

    try {
        Class cls = builder.make()
                .load(StructClassBuilder.class.getClassLoader())
                .getLoaded();

        Object obj = cls.newInstance();
        cls.getDeclaredMethod("method").invoke(obj, args);
    } catch (Exception e1) {
        e1.printStackTrace();
    }

}
person Marpa    schedule 03.11.2017