Support abstract @Configuration classes without @Bean methods again
Historically, @Configuration classes that did not declare @Bean methods were allowed to be abstract. However, the changes made in 76a6b9ea79 introduced a regression that prevents such classes from being abstract, resulting in a BeanInstantiationException. This change in behavior is caused by the fact that such a @Configuration class is no longer replaced by a concrete subclass created dynamically by CGLIB. This commit restores support for abstract @Configuration classes without @Bean methods by modifying the "no enhancement required" check in ConfigurationClassParser. See gh-34486 Closes gh-34663
This commit is contained in:
parent
36d9357f94
commit
044258f085
|
@ -179,8 +179,9 @@ class ConfigurationClassParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Downgrade to lite (no enhancement) in case of no instance-level @Bean methods.
|
// Downgrade to lite (no enhancement) in case of no instance-level @Bean methods.
|
||||||
if (!configClass.hasNonStaticBeanMethods() && ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(
|
if (!configClass.getMetadata().isAbstract() && !configClass.hasNonStaticBeanMethods() &&
|
||||||
bd.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE))) {
|
ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(
|
||||||
|
bd.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE))) {
|
||||||
bd.setAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE,
|
bd.setAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE,
|
||||||
ConfigurationClassUtils.CONFIGURATION_CLASS_LITE);
|
ConfigurationClassUtils.CONFIGURATION_CLASS_LITE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,6 +129,22 @@ class ConfigurationClassPostProcessorTests {
|
||||||
assertThat(beanFactory.getDependentBeans("config")).contains("bar");
|
assertThat(beanFactory.getDependentBeans("config")).contains("bar");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test // gh-34663
|
||||||
|
void enhancementIsPresentForAbstractConfigClassWithoutBeanMethods() {
|
||||||
|
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(AbstractConfigWithoutBeanMethods.class));
|
||||||
|
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
||||||
|
pp.postProcessBeanFactory(beanFactory);
|
||||||
|
RootBeanDefinition beanDefinition = (RootBeanDefinition) beanFactory.getBeanDefinition("config");
|
||||||
|
assertThat(beanDefinition.hasBeanClass()).isTrue();
|
||||||
|
assertThat(beanDefinition.getBeanClass().getName()).contains(ClassUtils.CGLIB_CLASS_SEPARATOR);
|
||||||
|
Foo foo = beanFactory.getBean("foo", Foo.class);
|
||||||
|
Bar bar = beanFactory.getBean("bar", Bar.class);
|
||||||
|
assertThat(bar.foo).isSameAs(foo);
|
||||||
|
assertThat(beanFactory.getDependentBeans("foo")).contains("bar");
|
||||||
|
String[] dependentsOfSingletonBeanConfig = beanFactory.getDependentBeans(SingletonBeanConfig.class.getName());
|
||||||
|
assertThat(dependentsOfSingletonBeanConfig).containsOnly("foo", "bar");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void enhancementIsNotPresentForProxyBeanMethodsFlagSetToFalse() {
|
void enhancementIsNotPresentForProxyBeanMethodsFlagSetToFalse() {
|
||||||
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(NonEnhancedSingletonBeanConfig.class));
|
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(NonEnhancedSingletonBeanConfig.class));
|
||||||
|
@ -181,7 +197,7 @@ class ConfigurationClassPostProcessorTests {
|
||||||
assertThat(bar.foo).isNotSameAs(foo);
|
assertThat(bar.foo).isNotSameAs(foo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test // gh-34486
|
||||||
void enhancementIsNotPresentWithEmptyConfig() {
|
void enhancementIsNotPresentWithEmptyConfig() {
|
||||||
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(EmptyConfig.class));
|
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(EmptyConfig.class));
|
||||||
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
||||||
|
@ -1195,6 +1211,12 @@ class ConfigurationClassPostProcessorTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Import(SingletonBeanConfig.class)
|
||||||
|
abstract static class AbstractConfigWithoutBeanMethods {
|
||||||
|
// This class intentionally does NOT declare @Bean methods.
|
||||||
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
static final class EmptyConfig {
|
static final class EmptyConfig {
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue