升级Spring Boot 3.2后AOT代码生成失败:不支持'?'
Spring Boot 3.2 + Java 21 下@MockBean触发AOT代码生成失败问题
环境与场景
- Spring Boot 3.2
- Java 21
- 项目使用Spring Data JDBC,仓库接口为标准Spring Data Repository类型(示例见下文)
- 测试类中通过
@MockBean模拟仓库接口,执行./gradlew build时,所有测试在AOT代码生成阶段失败;注释@MockBean相关代码后可正常构建
报错信息
Exception in thread "main" org.springframework.test.context.aot.TestContextAotException: Failed to generate AOT artifacts for test classes [<list of our classes>] at org.springframework.test.context.aot.TestContextAotGenerator.lambda$processAheadOfTime$5(TestContextAotGenerator.java:285) at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:986) at org.springframework.util.MultiValueMapAdapter.forEach(MultiValueMapAdapter.java:179) at org.springframework.test.context.aot.TestContextAotGenerator.processAheadOfTime(TestContextAotGenerator.java:243) at org.springframework.test.context.aot.TestContextAotGenerator.processAheadOfTime(TestContextAotGenerator.java:205) at org.springframework.test.context.aot.TestAotProcessor.performAotProcessing(TestAotProcessor.java:91) at org.springframework.test.context.aot.TestAotProcessor.doProcess(TestAotProcessor.java:72) at org.springframework.test.context.aot.TestAotProcessor.doProcess(TestAotProcessor.java:39) at org.springframework.context.aot.AbstractAotProcessor.process(AbstractAotProcessor.java:82) at org.springframework.boot.test.context.SpringBootTestAotProcessor.main(SpringBootTestAotProcessor.java:63) Caused by: org.springframework.test.context.aot.TestContextAotException: Failed to process test class [<failing test class>] for AOT at org.springframework.test.context.aot.TestContextAotGenerator.processAheadOfTime(TestContextAotGenerator.java:322) at org.springframework.test.context.aot.TestContextAotGenerator.lambda$processAheadOfTime$5(TestContextAotGenerator.java:276) ... 9 more Caused by: java.lang.IllegalArgumentException: Failed to generate code for '[[MockDefinition@5b5f61cc name = '', typeToMock = <Spring Data JDBC repository being mocked>, extraInterfaces = set[[empty]], answer = RETURNS_DEFAULTS, serializable = false, reset = AFTER]]' with type java.util.LinkedHashSet<?> at org.springframework.beans.factory.aot.BeanDefinitionPropertyValueCodeGenerator.generateCode(BeanDefinitionPropertyValueCodeGenerator.java:105) at org.springframework.beans.factory.aot.BeanDefinitionPropertiesCodeGenerator.generateValue(BeanDefinitionPropertiesCodeGenerator.java:257) at org.springframework.beans.factory.aot.BeanDefinitionPropertiesCodeGenerator.lambda$addConstructorArgumentValues$3(BeanDefinitionPropertiesCodeGenerator.java:179) at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:986) at java.base/java.util.Collections$UnmodifiableMap.forEach(Collections.java:1707) at org.springframework.beans.factory.aot.BeanDefinitionPropertiesCodeGenerator.addConstructorArgumentValues(BeanDefinitionPropertiesCodeGenerator.java:176) at org.springframework.beans.factory.aot.BeanDefinitionPropertiesCodeGenerator.generateCode(BeanDefinitionPropertiesCodeGenerator.java:126) at org.springframework.beans.factory.aot.DefaultBeanRegistrationCodeFragments.generateSetBeanDefinitionPropertiesCode(DefaultBeanRegistrationCodeFragments.java:176) at org.springframework.beans.factory.aot.BeanRegistrationCodeGenerator.generateCode(BeanRegistrationCodeGenerator.java:81) at org.springframework.beans.factory.aot.BeanDefinitionMethodGenerator.lambda$generateBeanDefinitionMethod$3(BeanDefinitionMethodGenerator.java:176) at org.springframework.aot.generate.GeneratedMethod.<init>(GeneratedMethod.java:54) at org.springframework.aot.generate.GeneratedMethods.add(GeneratedMethods.java:112) at org.springframework.aot.generate.GeneratedMethods.add(GeneratedMethods.java:89) at org.springframework.beans.factory.aot.BeanDefinitionMethodGenerator.generateBeanDefinitionMethod(BeanDefinitionMethodGenerator.java:169) at org.springframework.beans.factory.aot.BeanDefinitionMethodGenerator.generateBeanDefinitionMethod(BeanDefinitionMethodGenerator.java:89) at org.springframework.beans.factory.aot.BeanRegistrationsAotContribution.lambda$generateRegisterBeanDefinitionsMethod$2(BeanRegistrationsAotContribution.java:90) at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:986) at org.springframework.beans.factory.aot.BeanRegistrationsAotContribution.generateRegisterBeanDefinitionsMethod(BeanRegistrationsAotContribution.java:88) at org.springframework.beans.factory.aot.BeanRegistrationsAotContribution.lambda$applyTo$1(BeanRegistrationsAotContribution.java:73) at org.springframework.aot.generate.GeneratedMethod.<init>(GeneratedMethod.java:54) at org.springframework.aot.generate.GeneratedMethods.add(GeneratedMethods.java:112) at org.springframework.aot.generate.GeneratedMethods.add(GeneratedMethods.java:89) at org.springframework.beans.factory.aot.BeanRegistrationsAotContribution.applyTo(BeanRegistrationsAotContribution.java:72) at org.springframework.context.aot.BeanFactoryInitializationAotContributions.applyTo(BeanFactoryInitializationAotContributions.java:78) at org.springframework.context.aot.ApplicationContextAotGenerator.lambda$processAheadOfTime$0(ApplicationContextAotGenerator.java:58) at org.springframework.context.aot.ApplicationContextAotGenerator.withCglibClassHandler(ApplicationContextAotGenerator.java:67) at org.springframework.context.aot.ApplicationContextAotGenerator.processAheadOfTime(ApplicationContextAotGenerator.java:53) at org.springframework.test.context.aot.TestContextAotGenerator.processAheadOfTime(TestContextAotGenerator.java:318) ... 10 more Caused by: java.lang.IllegalArgumentException: Failed to generate code for '[MockDefinition@5b5f61cc name = '', typeToMock = <Spring Data JDBC repository being mocked>, extraInterfaces = set[[empty]], answer = RETURNS_DEFAULTS, serializable = false, reset = AFTER]' with type ? at org.springframework.beans.factory.aot.BeanDefinitionPropertyValueCodeGenerator.generateCodeForElement(BeanDefinitionPropertyValueCodeGenerator.java:114) at org.springframework.beans.factory.aot.BeanDefinitionPropertyValueCodeGenerator$CollectionDelegate.generateCollectionOf(BeanDefinitionPropertyValueCodeGenerator.java:351) at org.springframework.beans.factory.aot.BeanDefinitionPropertyValueCodeGenerator$SetDelegate.generateCollectionCode(BeanDefinitionPropertyValueCodeGenerator.java:450) > Task :processTestAot FAILED 10 actionable tasks: 1 executed, 9 up-to-date at org.springframework.beans.factory.aot.BeanDefinitionPropertyValueCodeGenerator$SetDelegate.generateCollectionCode(BeanDefinitionPropertyValueCodeGenerator.java:440) at org.springframework.beans.factory.aot.BeanDefinitionPropertyValueCodeGenerator$CollectionDelegate.generateCode(BeanDefinitionPropertyValueCodeGenerator.java:334) at org.springframework.beans.factory.aot.BeanDefinitionPropertyValueCodeGenerator.generateCode(BeanDefinitionPropertyValueCodeGenerator.java:132) at org.springframework.beans.factory.aot.BeanDefinitionPropertyValueCodeGenerator.generateCode(BeanDefinitionPropertyValueCodeGenerator.java:102) ... 37 more Caused by: java.lang.IllegalArgumentException: Code generation does not support ? at org.springframework.beans.factory.aot.BeanDefinitionPropertyValueCodeGenerator.generateCode(BeanDefinitionPropertyValueCodeGenerator.java:137) at org.springframework.beans.factory.aot.BeanDefinitionPropertyValueCodeGenerator.generateCodeForElement(BeanDefinitionPropertyValueCodeGenerator.java:111) ... 43 more
仓库示例代码
public interface FooRepository extends ListCrudRepository<Foo, UUID>, PagingAndSortingRepository<Foo, UUID> { }
解决与规避方案
方案1:升级Spring Boot版本
该问题是Spring Boot 3.2.x早期版本的已知缺陷,官方在3.2.2及后续版本中修复了@MockBean在测试AOT代码生成时的类型处理问题。直接升级到最新稳定版即可解决。
方案2:临时禁用测试AOT处理
若暂时无法升级版本,可在Gradle配置中跳过测试的AOT处理:
在build.gradle中添加:
// 禁用所有测试的AOT支持 tasks.withType(Test) { jvmArgs('-Dspring.aot.enabled=false') } // 或者直接跳过processTestAot任务 tasks.named('processTestAot') { enabled = false }
方案3:手动创建并注入Mock
替代@MockBean,用Mockito手动创建Mock实例,通过反射注入到测试目标类中,绕过Spring AOT对MockBean的处理逻辑:
@SpringBootTest class FooServiceTest { private FooRepository fooRepository = Mockito.mock(FooRepository.class); @Autowired private FooService fooService; @BeforeEach void setUp() { // 用反射将Mock注入到服务类中 ReflectionTestUtils.setField(fooService, "fooRepository", fooRepository); } // 测试方法示例 @Test void testFooMethod() { // 配置Mock行为 when(fooRepository.findById(any(UUID.class))).thenReturn(Optional.of(new Foo())); // 执行测试逻辑 Foo result = fooService.getFooById(UUID.randomUUID()); // 断言验证 assertNotNull(result); } }
内容的提问来源于stack exchange,提问作者Daniel Mikusa
相关产品推荐
相关产品推荐

