Задача состоит не в том, чтобы создать класс, вызывающий метод 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
класс, чтобы получить соответствующий экземпляр поиска. Этот ответ показывает решение, здесь - это другой подход.