Вызвать приватный метод Java ASM - PullRequest
2 голосов
/ 18 февраля 2020

Я хотел бы вызвать частный метод без использования Reflection: возможно ли подключить частный нативный метод с помощью ASM и вызвать его?

1 Ответ

2 голосов
/ 19 февраля 2020

Задача состоит не в том, чтобы создать класс, вызывающий метод private через ASM или аналогичный инструмент генерации байт-кода. Задача состоит в том, чтобы получить байт-код в JVM без отклонения верификатором.

Для OpenJDK / HotSpot есть sun.misc.Unsafe, который имеет метод defineAnonymousClass(Class<?>, byte[], Object[]), который используется для генерации классов доступа, например, классы времени выполнения, реализующие функциональные интерфейсы и вызывающие методы private syntheti c, содержащие тело лямбда-выражения.

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

MethodHandles.Lookup l = MethodHandles.privateLookupIn(Class.class, MethodHandles.lookup());
MethodHandle target = l.findSpecial(Class.class, "getDeclaredFields0",
    MethodType.methodType(Field[].class, boolean.class), Class.class);
BiFunction<Class<?>,Boolean,Field[]> a = (BiFunction)LambdaMetafactory.metafactory(
    l, "apply", MethodType.methodType(BiFunction.class), target.type().generic(),
    target, target.type().changeParameterType(1, Boolean.class))
    .getTarget().invokeExact();

Затем вы можете позвонить, например, a.apply(Class.class, false), который вызовет getDeclaredFields0 без Reflection.

privateLookupIn - это метод Java 9, который будет работать, если вы используете немодульный код или предоставите необходимую опцию --add-opens при запуске JVM, чтобы открыть java.base для вашего модуля. Появится предупреждение о доступе к Reflection, и правильно отметить, что такой доступ «будет отклонен в будущем выпуске». В любом случае, Как скрыть предупреждение «Незаконный отражающий доступ» в java 9 без аргумента JVM? может быть интересно.

Для Java 8 вам необходимо взломать Lookup класс, чтобы получить соответствующий экземпляр поиска. Этот ответ показывает решение, здесь - это другой подход.

...