Skip to content

Commit b5c82b8

Browse files
committed
Reject bean names with factory prefix for Bean Overrides
Closes gh-33674
1 parent c864afd commit b5c82b8

File tree

2 files changed

+35
-12
lines changed

2 files changed

+35
-12
lines changed

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

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,13 @@ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
9696
}
9797

9898
private void registerBeanOverride(ConfigurableListableBeanFactory beanFactory, OverrideMetadata overrideMetadata) {
99+
String beanName = overrideMetadata.getBeanName();
100+
Field field = overrideMetadata.getField();
101+
Assert.state(!BeanFactoryUtils.isFactoryDereference(beanName),() -> """
102+
Unable to override bean '%s' for field '%s.%s': a FactoryBean cannot be overridden. \
103+
To override the bean created by the FactoryBean, remove the '&' prefix.""".formatted(
104+
beanName, field.getDeclaringClass().getSimpleName(), field.getName()));
105+
99106
switch (overrideMetadata.getStrategy()) {
100107
case REPLACE_DEFINITION -> replaceDefinition(beanFactory, overrideMetadata, true);
101108
case REPLACE_OR_CREATE_DEFINITION -> replaceDefinition(beanFactory, overrideMetadata, false);
@@ -123,18 +130,16 @@ private void replaceDefinition(ConfigurableListableBeanFactory beanFactory, Over
123130
RootBeanDefinition pseudoBeanDefinition = createPseudoBeanDefinition(overrideMetadata);
124131

125132
String beanName = overrideMetadata.getBeanName();
126-
String beanNameIncludingFactory;
127133
BeanDefinition existingBeanDefinition = null;
128134
if (beanName == null) {
129-
beanNameIncludingFactory = getBeanNameForType(beanFactory, overrideMetadata, requireExistingDefinition);
130-
if (beanNameIncludingFactory == null) {
135+
beanName = getBeanNameForType(beanFactory, overrideMetadata, requireExistingDefinition);
136+
if (beanName == null) {
131137
// We need to generate a name for a nonexistent bean.
132138
beanName = beanNameGenerator.generateBeanName(pseudoBeanDefinition, registry);
133-
beanNameIncludingFactory = beanName;
134139
}
135140
else {
136141
// We are overriding an existing bean.
137-
beanName = BeanFactoryUtils.transformedBeanName(beanNameIncludingFactory);
142+
beanName = BeanFactoryUtils.transformedBeanName(beanName);
138143
existingBeanDefinition = beanFactory.getBeanDefinition(beanName);
139144
}
140145
}
@@ -149,7 +154,6 @@ else if (requireExistingDefinition) {
149154
with name [%s] and type [%s]."""
150155
.formatted(beanName, overrideMetadata.getBeanType()));
151156
}
152-
beanNameIncludingFactory = beanName;
153157
}
154158

155159
if (existingBeanDefinition != null) {
@@ -177,7 +181,7 @@ else if (Boolean.getBoolean(AbstractAotProcessor.AOT_PROCESSING)) {
177181

178182
Object override = overrideMetadata.createOverride(beanName, existingBeanDefinition, null);
179183
overrideMetadata.track(override, beanFactory);
180-
this.overrideRegistrar.registerNameForMetadata(overrideMetadata, beanNameIncludingFactory);
184+
this.overrideRegistrar.registerNameForMetadata(overrideMetadata, beanName);
181185

182186
// Now we have an instance (the override) that we can register. At this stage, we don't
183187
// expect a singleton instance to be present. If for some reason a singleton instance

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

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,18 @@
5656
*/
5757
class BeanOverrideBeanFactoryPostProcessorTests {
5858

59+
@Test
60+
void beanNameWithFactoryBeanPrefixIsRejected() {
61+
AnnotationConfigApplicationContext context = createContext(FactoryBeanPrefixTestCase.class);
62+
63+
assertThatIllegalStateException()
64+
.isThrownBy(context::refresh)
65+
.withMessage("""
66+
Unable to override bean '&messageService' for field 'FactoryBeanPrefixTestCase.messageService': \
67+
a FactoryBean cannot be overridden. To override the bean created by the FactoryBean, remove the \
68+
'&' prefix.""");
69+
}
70+
5971
@Test
6072
void replaceBeanByNameWithMatchingBeanDefinition() {
6173
AnnotationConfigApplicationContext context = createContext(CaseByName.class);
@@ -348,6 +360,18 @@ private AnnotationConfigApplicationContext createContext(Class<?> testClass) {
348360
}
349361

350362

363+
@FunctionalInterface
364+
interface MessageService {
365+
String getMessage();
366+
}
367+
368+
static class FactoryBeanPrefixTestCase {
369+
370+
@DummyBean(beanName = "&messageService")
371+
MessageService messageService;
372+
373+
}
374+
351375
static class CaseByName {
352376

353377
@DummyBean(beanName = "descriptionBean")
@@ -464,11 +488,6 @@ public boolean isSingleton() {
464488
}
465489
}
466490

467-
@FunctionalInterface
468-
interface MessageService {
469-
String getMessage();
470-
}
471-
472491
static class MessageServiceTestCase {
473492

474493
@TestBean(name = "messageServiceBean")

0 commit comments

Comments
 (0)