Перехватывать все методы/конструкторы/геттеры/сеттеры из определенного пространства имен

У меня есть агент Java, реализованный следующим образом:

public static void premain(String args, Instrumentation instrumentation) throws ClassNotFoundException {
    new AgentBuilder.Default()
      .type(isSubTypeOf(Object.class).and(nameStartsWith("com.my.domain")))
      .transform(new Transformer5())
      .installOn(instrumentation);
}

а затем класс преобразования:

public class Transformer5 implements AgentBuilder.Transformer {
    public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader) {
        return builder.method(any().and(isDeclaredBy(typeDescription)))
                      .intercept(MethodDelegation.to(Interc4.class));
    }
}

и перехватчик:

public class Interc4 {

    static String indent = "";

    @RuntimeType
    @BindingPriority(BindingPriority.DEFAULT * 3)
    public static Object intercept(@SuperCall Callable<?> zuper, 
                                   @AllArguments Object[] allArguments, 
                                   @Origin String method) throws Exception {

        System.out.println(indent + "Intercepted4 M" + method);

        try {
            indent += "  ";
            return zuper.call();
        } finally {
            //post process
            indent = indent.substring(0, indent.length()-2);
        }

    }

}

Проблема в том, что он не перехватывает конструкторы, а также выдает такие ошибки.

Невозможно определить закрытый или не виртуальный метод «лямбда $ static $ 1» для типа интерфейса

Каков наилучший способ сделать перехватчик, который будет проксировать каждый метод в классе из некоторого домена (я хочу иметь возможность получить имя метода, проверить аргументы метода (если есть) и просто переслать выполнение).


person Marko Kraljevic    schedule 22.07.2016    source источник


Ответы (1)


Есть две причины происходящего.

  1. Cannot define non-public or non-virtual method 'lambda$static$1' for interface type вызвано ошибкой проверки в Byte Buddy. Я собираюсь исправить это для следующего выпуска. А пока вы можете отключить проверку с помощью new AgentBuilder.Default(new ByteBuddy().with(TypeValidation.DISABLED)).

  2. Вы явно перехватываете методы только путем сопоставления через .method( ... ). Вы можете перехватывать конструкторы с помощью .constructor( ... ) или любых вызываемых с помощью .invokable( ... ). Однако вы не сможете использовать свой перехватчик для конструкторов, где вызов суперметода должен быть жестко запрограммирован. Однако вы можете разделить свой перехватчик на два бита:

    class Interceptor {
      public static void before() { ... }
      public static void after() { ... }
    }
    

    с использованием

    .intercept(MethodDelegation.to(Interceptor.class).filter(named("before")
       .andThen(SuperMethodCall.INSTANCE
       .andThen(MethodDelegation.to(Interceptor.class).filter(named("after"))))
    

Таким образом, Byte Buddy может жестко закодировать вызов суперконструктора и при этом вызвать методы before и after. Обратите внимание, что аннотация @This недоступна для метода before.

person Rafael Winterhalter    schedule 24.07.2016