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

时间:2015-11-26 16:04:31

标签: java bytecode instrumentation byte-buddy

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

这个想法是创造一些类似于通用的记录飞行记录器"用于方法调用及其在foo等特定包中的类的参数。

我在应用程序启动时使用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类。

但是对于像{/ p>这样的奇怪java.lang.VerifyError的经典(动态)Groovy类,它失败了

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)    
    ...

这里发生了什么? Byte Buddy是否支持Groovy方法拦截?

1 个答案:

答案 0 :(得分:2)

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

为了克服这个限制,Byte Buddy 0.7.2(今天发布)包含一个ClassVisitorWrapper,用于修复现代字节代码,以便在注册添加的{时,由兼容的遗留信息表示{1}}。这种调整并不完美,因为如果缺少一个类,它将导致TypeConstantAdjustment,其中JLS通常需要ClassNotFoundException。如果您能忍受此限制,则可以使用它。如果需要(Java 4或更早版本),调整将自行发现,因此您可以根据需要添加它。