我们正在开发一个JVMTI Java Agent,用于检测java类文件。其中一小部分(显然)是本机c ++代码,但较大的部分是Java代码,它通过网络加载并从本机代理代码调用。 我们使用代码覆盖工具来收集java部分的测试覆盖率,该部分用于源代码检测。
现在当我们的代理启动时,一些类被初始化,特别是java.lang.ref.Reference,它启动一个Thread。我们的代理使用自定义java代码来检测Thread start方法,该代码由代码覆盖工具进行检测。 coverage工具在我们的java代理程序代码中放置了一些带有静态初始化程序的静态内部类,因此这会在java.lang.ref.Reference初始化时执行。
问题是,此时(当java.lang.ref.Reference被初始化时),JVM的一些基本功能尚未到位。具体来说,代码覆盖率工具初始化程序想要访问System.getProperty(String name),但System.props仍为null,因此调用会导致NullPointerException。 这导致代码覆盖工具的静态内部类被保留为未初始化,该类处于状态initialization_error中,结果为NoClassDefFoundError。每个后续访问此类都会导致NoClassDefFoundError。
我现在的意图是忽略这个初始初始化错误,并等到VM_Start,然后将相关类的ClassState重置为“linked”。这样我希望JVM会在后续访问类时再次尝试初始化类。
有没有人有想法,如果可以从JVMTI Agent完成,并给我一些建议如何做到这一点?
答案 0 :(得分:0)
从您的描述中,我感觉您的代码太紧密耦合了。你真正想要的是在开始测试之前有一个初始化的Java VM 。
因此,我建议将代码分为三类:
,而不是使用本机代码和代理null
的方法)。对于测试,实例化模型类。覆盖测试所需的方法,以便返回需要测试的代码所需的模拟数据对象(有关模拟测试的示例,请参阅mockito)
或者,在测试用例中测试Java加载代码。在所有其他测试中,将类添加到类路径中,并像往常一样实例化它。
答案 1 :(得分:0)
VM_Start之后的RetransformClasses将为Reference生成一个新的类加载挂钩,允许您在安全的VM阶段中执行检测...只需重新转换引用或getLoadedClasses并重新转换它们。