我们正在开发 JVMTI Java 代理,用于检测 Java 类文件。其中一小部分(显然)是 native C++ 代码,但较大部分是 Java 代码,它通过网络加载并从 native 代理代码调用。 我们使用代码覆盖率工具来收集 java 部分的测试覆盖率,该部分执行源代码检测。
现在,当我们的代理启动时,一些类会被初始化,特别是 java.lang.ref.Reference,它会启动一个线程。我们的代理使用自定义 java 代码来检测线程启动方法,该代码由代码覆盖率工具检测。 覆盖工具在我们的 java 代理代码中放置了一些带有静态初始化器的静态内部类,因此它会作为 java.lang.ref.Reference 初始化的结果而被执行。
问题是,此时(当 java.lang.ref.Reference 初始化时),JVM 的一些基本功能尚未到位。具体来说,代码覆盖工具初始值设定项想要访问 System.getProperty(String name),但 System.props 仍然为 null,因此调用会导致 NullPointerException。 这导致代码覆盖工具的静态内部类未初始化,该类处于初始化错误状态,结果为NoClassDefFoundError。每次对此类的后续访问都会导致 NoClassDefFoundError。
我现在的意图是忽略这个初始初始化错误,并等到VM_Start,然后将相关类的ClassState重置为“linked”。这样我希望 JVM 在后续访问该类时会尝试再次初始化该类。
有谁知道是否可以通过 JVMTI 代理来完成此操作,并给我一些如何完成此操作的建议?
最佳答案
从你的描述中,我感觉你的代码耦合得太紧了。您真正想要的是在开始测试之前拥有一个已初始化的 Java VM。
因此,我建议将代码分为三个类,而不是搞乱 native 代码和代理:
- 抽象基类中的 Java 代码
- 扩展基类并使用 native C++ 代码实现抽象方法的类。理想情况下,此类不应包含除 native 方法声明之外的任何 Java 代码。
- 用于测试的模型类,它定义了具有空主体(或仅返回
null
)的相同方法。
对于测试,实例化模型类。覆盖测试所需的方法,以便您可以返回被测代码所需的模拟数据对象(有关模拟测试的一些示例,请参阅 mockito)
或者,在测试用例中测试 Java 加载代码。在所有其他测试中,将类添加到类路径中并像往常一样实例化它。
关于java - 重新初始化 Java 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5311850/