Как предотвратить лямбда-выражения, определенные в Java-агенте, нарушить работу приложения, к которому он присоединен? - PullRequest
1 голос
/ 02 июня 2019

Если я объявлю этот совет в моем агенте:

public static class SequenceAdvice {
    @Advice.OnMethodEnter
    static void enter(@Advice.This Object thiz, 
                      @Advice.Origin Method method, 
                      @Advice.AllArguments Object... args) {
        StackWalker walker = 
            StackWalker.getInstance(RETAIN_CLASS_REFERENCE);

        walker.forEach(sf -> 
            System.out.println(sf.getClassName() + "." + sf.getMethodName())
        );
    }
}

как javac скомпилирует лямбда-выражение в закрытый метод (по крайней мере, в OpenJDK 11):

public class SequenceAgent$SequenceAdvice {
  ...
  private static void lambda$enter$0(java.lang.StackWalker$StackFrame);
  ...
}

когда агент присоединен к программе и программа выполняется, он вызывает сбой программы:

Exception in thread "main" java.lang.IllegalAccessError: 
  class DemoController tried to access private method
    SequenceAgent$SequenceAdvice.lambda$enter$0(
       Ljava/lang/StackWalker$StackFrame;)V 
         (DemoController and SequenceAgent$SequenceAdvice 
          are in unnamed module of loader 'app')
    at DemoController.getDemos(DemoController.java)
    at DemoMain.main(DemoMain.java:13)

В идеале я предпочитаю не использовать объекты вместо лямбда-выражений, чтобы обойти это:

public static class SequenceAdvice {

    public static Consumer<StackWalker.StackFrame> SF_CONSUMER = 
        new Consumer<>() {
            @Override
            public void accept(StackWalker.StackFrame sf) {
                System.out.println(sf.getClassName() + "." + sf.getMethodName());
            }
    };

    @Advice.OnMethodEnter
    static void enter(@Advice.This Object thiz, 
                      @Advice.Origin Method method, 
                      @Advice.AllArguments Object... args) {
        StackWalker walker = StackWalker.getInstance(RETAIN_CLASS_REFERENCE);

        walker.forEach(SF_CONSUMER);
    }
}

Пользовательская разрешающая политика безопасности, похоже, не разрешает эту ошибку:

grant {
    permission java.security.AllPermission;
};

Есть ли способ временно отключить эту категорию проверок безопасности (например, "доступ к приватному методу" )

1 Ответ

1 голос
/ 03 июня 2019

Вы не можете использовать лямбда-выражения из совета.Лямбда-выражение будет частью класса совета, который не доступен целевому классу.Вместо этого вам нужно определить вспомогательный класс, который определяет код лямбда-выражений в открытых методах, и ссылаться на эти методы как на ссылки на методы.

Затем необходимо либо:

  1. добавить этот классв загрузчик классов начальной загрузки через Instrumentation.
  2. добавьте этот класс в загрузчик классов инструментированного класса через Injector.

Byte Buddy. Таким образом, ссылки доступныв инструментированный класс и может быть выполнен.

...