Skip to content

Commit 5ddeb06

Browse files
committed
Skip pseudo bean definition registration during AOT processing
Prior to this commit, AOT processing failed for tests that made use of the Bean Override feature to "override" a nonexistent bean. The reason is that we register a "pseudo" bean definition as a placeholder for a nonexistent bean, and our AOT support cannot automatically convert that "pseudo" bean definition to a functional bean definition for use at AOT runtime. To address that, this commit skips registration of "pseudo" bean definitions during AOT processing, and by doing so we enable the JVM runtime and AOT runtime to operate with the same semantics. See gh-32933
1 parent ce8e06c commit 5ddeb06

File tree

2 files changed

+24
-1
lines changed

2 files changed

+24
-1
lines changed

spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideBeanFactoryPostProcessor.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.springframework.beans.factory.support.DefaultBeanNameGenerator;
3636
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
3737
import org.springframework.beans.factory.support.RootBeanDefinition;
38+
import org.springframework.context.aot.AbstractAotProcessor;
3839
import org.springframework.core.Ordered;
3940
import org.springframework.core.ResolvableType;
4041
import org.springframework.lang.Nullable;
@@ -105,6 +106,12 @@ private void registerBeanOverride(ConfigurableListableBeanFactory beanFactory, O
105106
private void replaceDefinition(ConfigurableListableBeanFactory beanFactory, OverrideMetadata overrideMetadata,
106107
boolean enforceExistingDefinition) {
107108

109+
// NOTE: This method supports 3 distinct scenarios which must be accounted for.
110+
//
111+
// 1) JVM runtime
112+
// 2) AOT processing
113+
// 3) AOT runtime
114+
108115
if (!(beanFactory instanceof BeanDefinitionRegistry registry)) {
109116
throw new IllegalStateException("Cannot process bean override with a BeanFactory " +
110117
"that doesn't implement BeanDefinitionRegistry: " + beanFactory.getClass().getName());
@@ -147,12 +154,24 @@ else if (enforceExistingDefinition) {
147154

148155
if (existingBeanDefinition != null) {
149156
// Validate the existing bean definition.
157+
//
158+
// Applies during "JVM runtime", "AOT processing", and "AOT runtime".
150159
validateBeanDefinition(beanFactory, beanName);
151160
}
161+
else if (Boolean.getBoolean(AbstractAotProcessor.AOT_PROCESSING)) {
162+
// There was no existing bean definition, but during "AOT processing" we
163+
// do not register the "pseudo" bean definition since our AOT support
164+
// cannot automatically convert that to a functional bean definition for
165+
// use at "AOT runtime". Furthermore, by not registering a bean definition
166+
// for a nonexistent bean, we allow the "JVM runtime" and "AOT runtime"
167+
// to operate the same in the following else-block.
168+
}
152169
else {
153170
// There was no existing bean definition, so we register the "pseudo" bean
154171
// definition to ensure that a suitable bean definition exists for the given
155172
// bean name for proper autowiring candidate resolution.
173+
//
174+
// Applies during "JVM runtime" and "AOT runtime".
156175
registry.registerBeanDefinition(beanName, pseudoBeanDefinition);
157176
}
158177

@@ -163,6 +182,11 @@ else if (enforceExistingDefinition) {
163182
// Now we have an instance (the override) that we can register. At this stage, we don't
164183
// expect a singleton instance to be present. If for some reason a singleton instance
165184
// already exists, the following will throw an exception.
185+
//
186+
// As a bonus, by manually registering a singleton during "AOT processing", we allow
187+
// GenericApplicationContext's preDetermineBeanType() method to transparently register
188+
// runtime hints for a proxy generated by the above createOverride() invocation --
189+
// for example, when @MockitoBean creates a mock based on a JDK dynamic proxy.
166190
beanFactory.registerSingleton(beanName, override);
167191
}
168192

spring-test/src/test/java/org/springframework/test/context/aot/AotIntegrationTests.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,6 @@ void endToEndTestsForEntireSpringTestModule() {
155155
runEndToEndTests(testClasses, false);
156156
}
157157

158-
@Disabled("Comment out to run Bean Override integration tests in AOT mode")
159158
@Test
160159
void endToEndTestsForBeanOverrides() {
161160
List<Class<?>> testClasses = createTestClassScanner()

0 commit comments

Comments
 (0)