使用 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.VerifyError
s 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 或更早版本),因此您可以在需要时简单地添加它。
我尝试使用 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 类。
但对于经典(动态)Groovy 类 和奇怪的 java.lang.VerifyError
s 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 或更早版本),因此您可以在需要时简单地添加它。