Я проверяю, могу ли я использовать ByteBuddy для замены какого-нибудь громоздкого кода ASM меньшим, более элегантным решением. Одна часть состоит в том, чтобы «обернуть» собственные методы, то есть префикс любого существующего нативного метода в классе и предоставить новый, неродный метод с тем же именем и подписью, вызывающий префиксный. Все это может произойти во время сборки, поэтому мне не нужны какие-либо агенты, не нужно беспокоиться о возможных изменениях схемы классов и т. Д.ByteBuddy - Rebasing native методы
Из документации это похоже на случай переустановки, когда ByteBuddy оставляет копию оригинала метод и дает возможность назвать его через @SuperCall
.
Кроме того, не имея возможности влиять на новые имена для оригинальных методов (они должны иметь префикс, а не постфикса) следующий код приводит к ошибке ниже:
new ByteBuddy()
.rebase(typePool.describe("test.ClassWithNatives").resolve(), ClassFileLocator.ForClassLoader.ofClassPath())
.method(named("someNativeMethod"))
.intercept(MethodDelegation.to(NativeInterceptor.class))
.make()
.load(getClass().getClassLoader())
.getLoaded();
.
Exception in thread "main" java.lang.IllegalStateException: Error invoking java.lang.ClassLoader#findClass
at net.bytebuddy.dynamic.loading.ClassInjector$UsingReflection$Dispatcher$Direct.defineClass(ClassInjector.java:410)
at net.bytebuddy.dynamic.loading.ClassInjector$UsingReflection.inject(ClassInjector.java:183)
at net.bytebuddy.dynamic.loading.ClassLoadingStrategy$Default$InjectionDispatcher.load(ClassLoadingStrategy.java:187)
at net.bytebuddy.dynamic.loading.ClassLoadingStrategy$Default.load(ClassLoadingStrategy.java:120)
at net.bytebuddy.dynamic.TypeResolutionStrategy$Passive.initialize(TypeResolutionStrategy.java:79)
at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:4376)
at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:4366)
at ByteBuddyTest.wrapNatives(ByteBuddyTest.java:45)
at ByteBuddyTest.start(ByteBuddyTest.java:22)
at ByteBuddyTest.main(ByteBuddyTest.java:16)
Caused by: java.lang.ClassFormatError: Absent Code attribute in method that is not native or abstract in class file ClassWithNatives
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at net.bytebuddy.dynamic.loading.ClassInjector$UsingReflection$Dispatcher$Direct.defineClass(ClassInjector.java:406)
... 9 more
Возможно ли реализовать такой сценарий с помощью ByteBuddy?
Может быть, я что-то отсутствует, но для меня это приводит к той же ошибки. Я увеличил лямбда, чтобы получить «ReceiverTypeDefinition» и сохранил 'byte []' в файле, прежде чем возвращать определение. Из байтового кода я увидел, что флаг «native» удален из списка модификаторов класса, но не добавлен код для «Interceptor». Также не существует переименованного нативного метода (кроме того, что префикс native-метода, передаваемый ByteBuddy, кажется, используется только для инструментария, но на самом деле не влияет на то, как ByteBuddy генерирует новые имена методов, не так ли?) –
Вы правы, я просто нашел здесь ошибку, которую я разрешаю в версии 1.6.6. Я подталкиваю его в следующие часы. –
Приятно, я только что проверил. Работает с агентом сейчас! Также через 'new ByteBuddy()' собственный метод теперь перехвачен правильно, просто потому, что я, очевидно, не могу вызвать исходный метод, потому что он не префикс. Не уверен, что это сломает архитектуру, но было бы так «неправильно» иметь что-то вроде «нового ByteBuddy(). EnableNativeMethodPrefix (« prefix »)'? Также я был бы признателен, если бы вы могли поделиться некоторыми сведениями о том, как на самом деле вызывается prefixed native, поскольку я не смог найти собственный метод, используя 'javap', просто' invokestatic'. Но где теперь определяется метод? –