Reject bean names with factory prefix for Bean Overrides
Closes gh-33674
This commit is contained in:
parent
c864afd6fe
commit
b5c82b8dcb
|
@ -96,6 +96,13 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerBeanOverride(ConfigurableListableBeanFactory beanFactory, OverrideMetadata overrideMetadata) {
|
private void registerBeanOverride(ConfigurableListableBeanFactory beanFactory, OverrideMetadata overrideMetadata) {
|
||||||
|
String beanName = overrideMetadata.getBeanName();
|
||||||
|
Field field = overrideMetadata.getField();
|
||||||
|
Assert.state(!BeanFactoryUtils.isFactoryDereference(beanName),() -> """
|
||||||
|
Unable to override bean '%s' for field '%s.%s': a FactoryBean cannot be overridden. \
|
||||||
|
To override the bean created by the FactoryBean, remove the '&' prefix.""".formatted(
|
||||||
|
beanName, field.getDeclaringClass().getSimpleName(), field.getName()));
|
||||||
|
|
||||||
switch (overrideMetadata.getStrategy()) {
|
switch (overrideMetadata.getStrategy()) {
|
||||||
case REPLACE_DEFINITION -> replaceDefinition(beanFactory, overrideMetadata, true);
|
case REPLACE_DEFINITION -> replaceDefinition(beanFactory, overrideMetadata, true);
|
||||||
case REPLACE_OR_CREATE_DEFINITION -> replaceDefinition(beanFactory, overrideMetadata, false);
|
case REPLACE_OR_CREATE_DEFINITION -> replaceDefinition(beanFactory, overrideMetadata, false);
|
||||||
|
@ -123,18 +130,16 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
|
||||||
RootBeanDefinition pseudoBeanDefinition = createPseudoBeanDefinition(overrideMetadata);
|
RootBeanDefinition pseudoBeanDefinition = createPseudoBeanDefinition(overrideMetadata);
|
||||||
|
|
||||||
String beanName = overrideMetadata.getBeanName();
|
String beanName = overrideMetadata.getBeanName();
|
||||||
String beanNameIncludingFactory;
|
|
||||||
BeanDefinition existingBeanDefinition = null;
|
BeanDefinition existingBeanDefinition = null;
|
||||||
if (beanName == null) {
|
if (beanName == null) {
|
||||||
beanNameIncludingFactory = getBeanNameForType(beanFactory, overrideMetadata, requireExistingDefinition);
|
beanName = getBeanNameForType(beanFactory, overrideMetadata, requireExistingDefinition);
|
||||||
if (beanNameIncludingFactory == null) {
|
if (beanName == null) {
|
||||||
// We need to generate a name for a nonexistent bean.
|
// We need to generate a name for a nonexistent bean.
|
||||||
beanName = beanNameGenerator.generateBeanName(pseudoBeanDefinition, registry);
|
beanName = beanNameGenerator.generateBeanName(pseudoBeanDefinition, registry);
|
||||||
beanNameIncludingFactory = beanName;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// We are overriding an existing bean.
|
// We are overriding an existing bean.
|
||||||
beanName = BeanFactoryUtils.transformedBeanName(beanNameIncludingFactory);
|
beanName = BeanFactoryUtils.transformedBeanName(beanName);
|
||||||
existingBeanDefinition = beanFactory.getBeanDefinition(beanName);
|
existingBeanDefinition = beanFactory.getBeanDefinition(beanName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -149,7 +154,6 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
|
||||||
with name [%s] and type [%s]."""
|
with name [%s] and type [%s]."""
|
||||||
.formatted(beanName, overrideMetadata.getBeanType()));
|
.formatted(beanName, overrideMetadata.getBeanType()));
|
||||||
}
|
}
|
||||||
beanNameIncludingFactory = beanName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (existingBeanDefinition != null) {
|
if (existingBeanDefinition != null) {
|
||||||
|
@ -177,7 +181,7 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
|
||||||
|
|
||||||
Object override = overrideMetadata.createOverride(beanName, existingBeanDefinition, null);
|
Object override = overrideMetadata.createOverride(beanName, existingBeanDefinition, null);
|
||||||
overrideMetadata.track(override, beanFactory);
|
overrideMetadata.track(override, beanFactory);
|
||||||
this.overrideRegistrar.registerNameForMetadata(overrideMetadata, beanNameIncludingFactory);
|
this.overrideRegistrar.registerNameForMetadata(overrideMetadata, beanName);
|
||||||
|
|
||||||
// Now we have an instance (the override) that we can register. At this stage, we don't
|
// Now we have an instance (the override) that we can register. At this stage, we don't
|
||||||
// expect a singleton instance to be present. If for some reason a singleton instance
|
// expect a singleton instance to be present. If for some reason a singleton instance
|
||||||
|
|
|
@ -56,6 +56,18 @@ import static org.mockito.Mockito.mock;
|
||||||
*/
|
*/
|
||||||
class BeanOverrideBeanFactoryPostProcessorTests {
|
class BeanOverrideBeanFactoryPostProcessorTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void beanNameWithFactoryBeanPrefixIsRejected() {
|
||||||
|
AnnotationConfigApplicationContext context = createContext(FactoryBeanPrefixTestCase.class);
|
||||||
|
|
||||||
|
assertThatIllegalStateException()
|
||||||
|
.isThrownBy(context::refresh)
|
||||||
|
.withMessage("""
|
||||||
|
Unable to override bean '&messageService' for field 'FactoryBeanPrefixTestCase.messageService': \
|
||||||
|
a FactoryBean cannot be overridden. To override the bean created by the FactoryBean, remove the \
|
||||||
|
'&' prefix.""");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void replaceBeanByNameWithMatchingBeanDefinition() {
|
void replaceBeanByNameWithMatchingBeanDefinition() {
|
||||||
AnnotationConfigApplicationContext context = createContext(CaseByName.class);
|
AnnotationConfigApplicationContext context = createContext(CaseByName.class);
|
||||||
|
@ -348,6 +360,18 @@ class BeanOverrideBeanFactoryPostProcessorTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
interface MessageService {
|
||||||
|
String getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class FactoryBeanPrefixTestCase {
|
||||||
|
|
||||||
|
@DummyBean(beanName = "&messageService")
|
||||||
|
MessageService messageService;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static class CaseByName {
|
static class CaseByName {
|
||||||
|
|
||||||
@DummyBean(beanName = "descriptionBean")
|
@DummyBean(beanName = "descriptionBean")
|
||||||
|
@ -464,11 +488,6 @@ class BeanOverrideBeanFactoryPostProcessorTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
interface MessageService {
|
|
||||||
String getMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
static class MessageServiceTestCase {
|
static class MessageServiceTestCase {
|
||||||
|
|
||||||
@TestBean(name = "messageServiceBean")
|
@TestBean(name = "messageServiceBean")
|
||||||
|
|
Loading…
Reference in New Issue