ByteBuddy - 重新定位原生方法

时间:2017-01-24 00:17:59

标签: java byte-buddy

我正在检查是否可以使用ByteBuddy用更小,更优雅的解决方案替换一些庞大的ASM代码。一部分是"包装"本机方法,意味着为类中的任何现有本机方法添加前缀,并提供具有相同名称和签名的新的非本机方法,并调用前缀方法。所有这些都可能在构建期间发生,因此我不需要任何代理,也不必担心潜在的类架构更改等等。

从文档中可以看出,如果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实现这样的场景吗?

1 个答案:

答案 0 :(得分:2)

只有通过Instrumentation使用Java代理才能实现。否则,JVM不知道如何重新定义具有必须遵循方法命名约定的本机适配器的本机方法。要使Byte Buddy工作,原始代码将被移动到另一种方法,以便从原始方法中调用,否则这是不可能的。

使用Java代理,可以运行:

new AgentBuilder.Default()
  .enableNativeMethodPrefix("foo")
  .type(named("test.ClassWithNatives"))
  .transform((b,t,c,m) -> b
    .method(named("someNativeMethod"))
    .intercept(MethodDelegation.to(NativeInterceptor.class))
  ).installOn(inst);