遇到从Byte Buddy 0.7.7迁移到1.0.2的问题

时间:2016-01-21 13:34:24

标签: java bytecode instrumentation byte-buddy

我在测试套件中遇到了一些问题,从Byte Buddy 0.7.7迁移到1.0.2

这是一个简化的例子:

public class ReproBug {

    @Test
    public void test() {
        ByteBuddyAgent.install();

        new AgentBuilder.Default().type(nameStartsWith("test"))
                .transform(new AgentBuilder.Transformer() {

                    @Override
                    public Builder<?> transform(Builder<?> builder, TypeDescription typeDescription) {

                        return builder.method(isDeclaredBy(typeDescription)).intercept(to(new Object() {

                            @RuntimeType
                            public void intercept(@SuperCall Callable<?> zuper, @Origin Method method) {
                                System.out.println("intercepting " + method.getName());
                            }
                        }));
                    }
                }).installOnByteBuddyAgent();

        MyClass.staticMethod();
    }
}

MyClass的代码:

class MyClass {
    public static void staticMethod() {
        System.out.println("in staticMethod");
    }
}

Byte Buddy 0.7.7没有报告任何错误,但是1.0.2我收到错误Cannot resolve type description for test.MyClass$auxiliary$dUGbkato

完整日志(来自AgentBuilder.Listener): http://pastebin.com/ytsQR5bi

请注意,该方法已被截获。

然而,在我的一些测试中,我获得了两倍的拦截量,因为它拦截了辅助类的方法call

1 个答案:

答案 0 :(得分:1)

添加侦听器时,我能够重现您的问题。 0.7.7和1.0.3之间的差异是Byte Buddy加载辅助类的时间。在1.0.3中,Byte Buddy加载一个类作为类的静态初始化器的一部分。这样,Byte Buddy确保没有辅助类触发已检测类的过早加载,例如,如果辅助类是检测类的子类型。在过去,这已经中止了仪器,Byte Buddy会因错误而失败。

作为一个含义,辅助类不再作为检测过程的一部分加载,并向代理API发出类加载事件,以使变换器变为活动状态。由于您的匹配器包含所有带有测试的类型,并且由于辅助类型与其检测类型在同一个包中,因此尝试检测这些辅助类型但无法找到类文件。因此,提出了例外。

在Byte Buddy 1.1.0(待发布)中,构建器API中有一个新方法ignoreTypes,其中可以指定任何应该完全忽略的类型。默认情况下,Byte Buddy现在将忽略任何合成类型。由于辅助类型是合成的,因此您在默认设置中不再遇到问题。

实际上,日志中的信息对您的程序没有任何影响。原始类型始终按照预期进行检测。问题只发生在Byte Buddy事实上可以检测你的辅助类型,其中重复的仪器正在发生。

一般情况下,在单元测试中,您应该始终确保在注册代理后删除变压器,例如:

Instrumentation inst = ByteBuddyAgent.install();
ClassFileTransformer cft = agentBuilder.installOnByteBuddyAgent();
try {
 // run test
finally {
  inst.removeTransformer(cft);
}

在测试中要特别针对哪些类进行拦截也是一种很好的做法,例如:通过指定一个类的完全限定名称。