升级至Java 17后JMock的Mockery.mock方法失效,求助解决
问题根源
Java 17的模块系统(JPMS)大幅收紧了反射访问权限,你使用的JMock依赖的cglib库试图通过反射调用ClassLoader.defineClass方法,但java.base模块并未向未命名模块开放java.lang包,导致触发InaccessibleObjectException。
解决方案
方案一:添加JVM启动参数临时开放权限
适合快速临时修复,无需修改代码:
- 在JUnit测试的JVM参数中添加以下配置:
--add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.lang.ClassLoader=ALL-UNNAMED - 如果使用Maven Surefire插件执行测试,在
pom.xml中配置插件参数:<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>3.1.2</version> <configuration> <argLine> --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.lang.ClassLoader=ALL-UNNAMED </argLine> </configuration> </plugin>
方案二:替换JMock的Imposteriser为ByteBuddy实现(推荐长期方案)
cglib对JPMS支持有限,JMock提供了基于ByteBuddy的Imposteriser,兼容性更好:
- 添加ByteBuddy依赖到项目:
<dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> <version>1.14.11</version> <scope>test</scope> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> <version>1.14.11</version> <scope>test</scope> </dependency> - 修改Mockery初始化代码,切换到ByteBuddyImposteriser:
如果你的import org.jmock.lib.bytebuddy.ByteBuddyImposteriser; import org.jmock.Mockery; // 创建Mockery实例时设置Imposteriser Mockery mockContext = new Mockery(); mockContext.setImposteriser(ByteBuddyImposteriser.INSTANCE); // 后续使用该实例创建Mock YourTargetClass mockObj = mockContext.mock(YourTargetClass.class, "customMockName");MetrixTestCase.mock方法封装了Mockery逻辑,直接在该方法内部修改Mockery的Imposteriser设置即可。
方案三:升级JMock至最新版本
检查JMock是否有更新版本(如2.13.x),新版本可能进一步优化JPMS适配,但核心解决思路仍需替换Imposteriser,因此方案二更直接。
内容的提问来源于stack exchange,提问作者CasaDelGato
相关产品推荐
相关产品推荐

