Use non-lenient constructor resolution mode for @Bean methods
Since @Bean methods are never used with externally specified constructor argument values but rather just with autowiring, the non-lenient constructor resolution mode is appropriate in case of an overloaded @Bean method, not performing any type difference weight checks. This change includes a refinement of Spring's existing non-lenient constructor resolution (which needs to be explicitly turned on and is therefore not well tested), narrowing the conditions for the ambiguity check (only in case of the same number of arguments and not for overridden methods).
Issue: SPR-10988
(cherry picked from commit b093b84)
This commit is contained in:
@@ -310,6 +310,7 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
|
||||
public ConfigurationClassBeanDefinition(ConfigurationClass configClass) {
|
||||
this.annotationMetadata = configClass.getMetadata();
|
||||
setLenientConstructorResolution(false);
|
||||
}
|
||||
|
||||
public ConfigurationClassBeanDefinition(RootBeanDefinition original, ConfigurationClass configClass) {
|
||||
|
||||
@@ -16,18 +16,20 @@
|
||||
|
||||
package org.springframework.context.annotation;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Tests regarding overloading and overriding of bean methods.
|
||||
* Related to SPR-6618.
|
||||
@@ -42,22 +44,27 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
* the most specific subclass bean method will always be the one that is invoked.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@SuppressWarnings("resource")
|
||||
public class BeanMethodPolymorphismTests {
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
|
||||
@Test
|
||||
public void beanMethodOverloadingWithoutInheritance() {
|
||||
|
||||
@SuppressWarnings({ "hiding" })
|
||||
@Configuration class Config {
|
||||
@Bean String aString() { return "na"; }
|
||||
@Bean String aString(Integer dependency) { return "na"; }
|
||||
}
|
||||
try {
|
||||
new AnnotationConfigApplicationContext(Config.class);
|
||||
fail("expected bean method overloading exception");
|
||||
} catch (BeanDefinitionParsingException ex) {
|
||||
assertTrue(ex.getMessage(), ex.getMessage().contains("2 overloaded @Bean methods named 'aString'"));
|
||||
}
|
||||
|
||||
this.thrown.expect(BeanDefinitionParsingException.class);
|
||||
this.thrown.expectMessage("overloaded @Bean methods named 'aString'");
|
||||
new AnnotationConfigApplicationContext(Config.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -65,12 +72,12 @@ public class BeanMethodPolymorphismTests {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SubConfig.class);
|
||||
assertThat(ctx.getBean(String.class), equalTo("overloaded5"));
|
||||
}
|
||||
static @Configuration class SuperConfig {
|
||||
@Bean String aString() { return "super"; }
|
||||
}
|
||||
static @Configuration class SubConfig {
|
||||
@Bean Integer anInt() { return 5; }
|
||||
@Bean String aString(Integer dependency) { return "overloaded"+dependency; }
|
||||
|
||||
@Test
|
||||
public void beanMethodOverloadingWithInheritanceAndList() {
|
||||
// SPR-11025
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SubConfigWithList.class);
|
||||
assertThat(ctx.getBean(String.class), equalTo("overloaded5"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,10 +90,6 @@ public class BeanMethodPolymorphismTests {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ShadowConfig.class);
|
||||
assertThat(ctx.getBean(String.class), equalTo("shadow"));
|
||||
}
|
||||
@Import(SubConfig.class)
|
||||
static @Configuration class ShadowConfig {
|
||||
@Bean String aString() { return "shadow"; }
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that polymorphic Configuration classes need not explicitly redeclare the
|
||||
@@ -110,6 +113,7 @@ public class BeanMethodPolymorphismTests {
|
||||
public TestBean testBean() {
|
||||
return new TestBean();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -117,4 +121,55 @@ public class BeanMethodPolymorphismTests {
|
||||
static class Config extends BaseConfig {
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class SuperConfig {
|
||||
|
||||
@Bean
|
||||
String aString() {
|
||||
return "super";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class SubConfig extends SuperConfig {
|
||||
|
||||
@Bean
|
||||
Integer anInt() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
@Bean
|
||||
String aString(Integer dependency) {
|
||||
return "overloaded" + dependency;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class SubConfigWithList extends SuperConfig {
|
||||
|
||||
@Bean
|
||||
Integer anInt() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
@Bean
|
||||
String aString(List<Integer> dependency) {
|
||||
return "overloaded" + dependency.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@Import(SubConfig.class)
|
||||
static class ShadowConfig {
|
||||
|
||||
@Bean
|
||||
String aString() {
|
||||
return "shadow";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user