使用 Byte Buddy 拦截对我的 Java 和 Groovy 代码的方法调用:奇怪 java.lang.VerifyError

Intercepting method calls to my Java and Groovy code using Byte Buddy: Strange java.lang.VerifyError

我尝试使用 Byte Buddy 0.7.1 从混合的 Java (8) 和 Groovy (2.4.5) 项目中拦截对 类 方法的调用。

我们的想法是在 foo.

等特定包中为方法调用及其参数 类 创建类似 "generic logging flight recorder" 的东西

我使用 Byte Buddy AgentBuilder 和我的自定义 LogInterceptor 在应用程序启动时执行此操作:

static {
  final Instrumentation inst = ByteBuddyAgent.install();
  new AgentBuilder.Default()
        .type(ElementMatchers.nameContainsIgnoreCase("foo")) // simplified
        .transform((builder, typeDescription) ->
                builder.method(ElementMatchers.any())
                        .intercept(MethodDelegation.to(LogInterceptor.class)
                           .andThen(SuperMethodCall.INSTANCE)))
        .installOn(inst);
}

public static class LogInterceptor {
  @RuntimeType
  public static void log(@Origin Method method, @AllArguments Object[] arg) throws Exception {
    // flightRecorder.log(...);
  }
}

方法拦截对所有 Java 类 都有效。它适用于所有带有 @CompileStatic 注释的 Groovy 类。

但对于经典(动态)Groovy 类 和奇怪的 java.lang.VerifyErrors like

它失败了
java.lang.VerifyError: (class: foo/MyInterceptedClass$barMethod, method: <clinit> signature: ()V) Illegal type in constant pool

    at java.lang.Class.getDeclaredConstructors0(Native Method)
    at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671)
    at java.lang.Class.getConstructor0(Class.java:3075)
    at java.lang.Class.getConstructor(Class.java:1825)
    at org.codehaus.groovy.reflection.ClassLoaderForClassArtifacts.defineClassAndGetConstructor(ClassLoaderForClassArtifacts.java:83)
    at org.codehaus.groovy.runtime.callsite.CallSiteGenerator.compileStaticMethod(CallSiteGenerator.java:246)
    at org.codehaus.groovy.reflection.CachedMethod.createStaticMetaMethodSite(CachedMethod.java:288)
    at org.codehaus.groovy.runtime.callsite.StaticMetaMethodSite.createStaticMetaMethodSite(StaticMetaMethodSite.java:114)
    at groovy.lang.MetaClassImpl.createStaticSite(MetaClassImpl.java:3385)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.createCallStaticSite(CallSiteArray.java:77)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.createCallSite(CallSiteArray.java:162)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:133)    
    ...

这是怎么回事?字节好友支持Groovy方法拦截吗?

出于我不知道的原因,Groovy 生成了 class 级 class 级别 1.4,其中 Byte Buddy 生成的某些字节代码构造是不合法的。这会生成一个 VerifyError。在使用 Byte Buddy 时,这当然不是一个非常有建设性的错误消息,这就是为什么 Byte Buddy 应用的 class 验证器现在检查是否非法使用 modern 概念Java字节码1.4.

为了克服这个限制,Byte Buddy 0.7.2(今天发布)包含一个 ClassVisitorWrapper,它修复了 modern 字节码,由兼容的旧指令表示注册时添加TypeConstantAdjustment。此调整并不完美,因为如果缺少 class,则会导致 ClassNotFoundException,而 JLS 通常需要 NoClassDefFoundError。如果您可以忍受此限制,则可以节省使用。调整会自行发现是否需要(Java 4 或更早版本),因此您可以在需要时简单地添加它。