ConstructorResolver error hints about mixing indexed and named args

This commit adds a note to an exception in `ConstructorResolver`'s
`autowireConstructor` method hinting that attention should be paid to
cases that mix indexed arguments and named arguments. This is especially
when inheriting bean definitions in xml.

Closes gh-29976
Close gh-PR
This commit is contained in:
Simon Baslé 2023-03-22 17:39:53 +01:00 committed by Juergen Hoeller
parent 59c65fa940
commit e262e98bab
2 changed files with 29 additions and 1 deletions

View File

@ -294,7 +294,9 @@ class ConstructorResolver {
}
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Could not resolve matching constructor on bean class [" + mbd.getBeanClassName() + "] " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities. " +
"You should also check the consistency of arguments when mixing indexed and named arguments, " +
"especially in case of bean definition inheritance)");
}
else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,

View File

@ -790,6 +790,32 @@ class DefaultListableBeanFactoryTests {
assertThat(mergedBeanDefinition1).as("Use cached merged bean definition").isSameAs(mergedBeanDefinition2);
}
@Test
void hintAtPossibleDuplicateArgumentsInParentAndChildWhenMixingIndexAndNamed() {
final String EXPECTED_NAME = "Juergen";
final int EXPECTED_AGE = 41;
RootBeanDefinition parentDefinition = new RootBeanDefinition(TestBean.class);
parentDefinition.setAbstract(true);
parentDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, EXPECTED_NAME);
ChildBeanDefinition childDefinition = new ChildBeanDefinition("parent");
childDefinition.getConstructorArgumentValues().addGenericArgumentValue(new ConstructorArgumentValues.ValueHolder(EXPECTED_NAME, null, "name"));
childDefinition.getConstructorArgumentValues().addGenericArgumentValue(new ConstructorArgumentValues.ValueHolder(EXPECTED_AGE, null, "age"));
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
factory.registerBeanDefinition("parent", parentDefinition);
factory.registerBeanDefinition("child", childDefinition);
assertThatExceptionOfType(BeanCreationException.class)
.isThrownBy(() -> factory.getBean("child", TestBean.class))
.withMessage("Error creating bean with name 'child': Could not resolve matching constructor on bean class " +
"[org.springframework.beans.testfixture.beans.TestBean] (hint: specify index/type/name arguments " +
"for simple parameters to avoid type ambiguities. " +
"You should also check the consistency of arguments when mixing indexed and named arguments, " +
"especially in case of bean definition inheritance)");
}
@Test
void getTypeWorksAfterParentChildMerging() {
RootBeanDefinition parentDefinition = new RootBeanDefinition(TestBean.class);