java - Byte Buddy 导致 IncompleteClassChangeError

标签 java bytecode byte-buddy

我使用 Byte Buddy (v0.5.2) 动态创建接口(interface)的“子类”(实际上,我想创建一个实现该接口(interface)的类)。在此类的实例上调用的所有方法都应重定向到另一个(拦截器)类。 我使用了以下代码(“TestInterface”是一个接口(interface),它声明了一个方法“sayHello”):

final Interceptor interceptor = new Interceptor();
Class<?> clazz = new ByteBuddy()
        .subclass(TestInterface.class)
        .method(any()).intercept(MethodDelegation.to(interceptor))
        .make()
        .load(TestInterface.class.getClassLoader(), ClassLoadingStrategy.Default.INJECTION)
        .getLoaded();
TestInterface instance = (TestInterface) clazz.newInstance();
instance.sayHello();

拦截器类如下所示:

public class Interceptor {

    public Object intercept(@Origin MethodHandle method, @AllArguments Object[] args) throws Throwable {
        ...
    }       

}

但是,当我尝试调用“sayHello”方法(代码示例的最后一行)时,我收到“IncompleteClassChangeError”。堆栈跟踪如下:

Exception in thread "main" java.lang.IllegalAccessError: no such method: byteuddytest.TestInterface.sayHello()void/invokeVirtual
    at java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(MethodHandleNatives.java:448)
    at bytebuddytest.TestInterface$ByteBuddy$0E9xusGs.sayHello(Unknown Source)
    at bytebuddytest.Main.main(Main.java:32)
Caused by: java.lang.IncompatibleClassChangeError: Found interface bytebuddytest.TestInterface, but class was expected
    at java.lang.invoke.MethodHandleNatives.resolve(Native Method)
    at java.lang.invoke.MemberName$Factory.resolve(MemberName.java:965)
    at java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:990)
    at java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:1387)
    at java.lang.invoke.MethodHandles$Lookup.linkMethodHandleConstant(MethodHandles.java:1732)
    at java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(MethodHandleNatives.java:442)
... 2 more

问题似乎与我的拦截器方法中使用“MethodHandle”参数有关。当我将类型更改为“方法”时,一切正常。但根据文档,由于性能原因,“MethodHandle”应该优先于“Method”。

该错误是由 Byte Buddy 中的错误引起的,还是在这种情况下我实际上应该使用“Method”参数?

最佳答案

使用Method参数并启用缓存。如果您首先遇到任何性能问题,这应该可以解决您的大部分性能问题。

参见javadoc对于@Origin:

public abstract boolean cacheMethod

If this value is set to true and the annotated parameter is a Method type, the value that is assigned to this parameter is cached in a static field. Otherwise, the instance is looked up from its defining Class on every invocation of the intercepted method.

Method look-ups are normally cached by its defining Class what makes a repeated look-up of a method little expensive. However, because Method instances are mutable by their AccessibleObject contact, any looked-up instance needs to be copied by its defining Class before exposing it. This can cause performance deficits when a method is for example called repeatedly in a loop. By enabling the method cache, this performance penalty can be avoided by caching a single Method instance for any intercepted method as a static field in the instrumented type.

关于java - Byte Buddy 导致 IncompleteClassChangeError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28099696/

相关文章:

Java JSR-303 无需字节码编织的自动 Bean 验证

java - Mockito 因使用无效参数名称异常启用的内联模拟而失败

java - 字节好友 : How to do method delegation/forwarding to a volatile field

java - 鱼眼中的哪个类/jar 文件 Hook 到 subversion 和 GIT?

java - 使用 node.getTextContent() 从 xml 获取值时无法删除空格

Python 2 和 3,字节码(pyo 和 pyc)是否向后兼容?

scala - 访问由 Scala REPL 创建的字节码

java - 如何使用数据存储 api 使用父实体键获取嵌套子实体

java - 使用不可变的享元跳过多余的验证

java - 使用 ASM 生成有效的 invokedynamic 指令