Quarkus 3中使用JMock Mock MapStruct Mapper时出现类转换异常
@QuarkusTest中Mock MapStruct Mapper的类型转换异常解决方案
问题重现
在@QuarkusTest环境下尝试用jMock Mock MapStruct Mapper,代码如下:
@RegisterExtension JUnit5Mockery mockery = new JUnit5Mockery() { { setImposteriser(ByteBuddyClassImposteriser.INSTANCE); setThreadingPolicy(new Synchroniser()); } }; MyMapper mockMyMapper = mockery.mock(MyMapper.class); QuarkusMock.installMockForType(mockMyMapper, MyMapper.class);
运行后触发类型转换异常:
java.lang.ClassCastException: class com.example.MyMapper$jMock$yRbf640e cannot be cast to class com.example.MyMapperImpl (com.example.MyMapper$jMock$yRbf640e is in unnamed module of loader org.jmock.internal.SearchingClassLoader @510bd87a; com.example.MyMapperImpl is in unnamed module of loader io.quarkus.bootstrap.classloading.QuarkusClassLoader @1dbd580)
问题根源
- MapStruct会自动生成Mapper接口的实现类
MyMapperImpl,Quarkus默认注入的是该实现类实例,而非接口实例。 - jMock生成的代理对象基于
MyMapper接口创建,但Quarkus尝试将其强制转换为MyMapperImpl类型。 - 代理类和实现类由不同类加载器加载,JVM判定为不同类型,最终抛出转换异常。
解决方法
方法一:改用Quarkus原生支持的Mockito
Quarkus对Mockito有内置集成,直接Mock实现类即可避免类加载器问题:
@QuarkusTest @MockBean(MyMapperImpl.class) MyMapper mockMyMapper; @Test void testBusinessLogic() { // 配置Mock行为 when(mockMyMapper.convert(any(Source.class))).thenReturn(new Target()); // 执行测试逻辑并验证 }
方法二:确保依赖注入接口而非实现类
检查业务代码中的注入逻辑,确保注入的是MyMapper接口而非MyMapperImpl:
@Inject MyMapper myMapper; // 正确:注入接口类型 // @Inject MyMapperImpl myMapper; // 错误:直接注入实现类会导致Mock匹配失败
这样Quarkus注入时会识别接口类型的Mock对象,不会触发强转操作。
方法三:调整jMock的类加载器配置
如果必须使用jMock,需让其生成的代理类使用Quarkus的类加载器:
@RegisterExtension JUnit5Mockery mockery = new JUnit5Mockery() { { setImposteriser(ByteBuddyClassImposteriser.INSTANCE); setThreadingPolicy(new Synchroniser()); // 指定类加载器为当前线程的上下文类加载器(即Quarkus类加载器) setClassLoader(Thread.currentThread().getContextClassLoader()); } };
同时配合接口注入的方式,即可解决类型转换问题。
内容的提问来源于stack exchange,提问作者gkephorus
相关产品推荐
相关产品推荐

