Import ConstructorResolver to handle null values

Previously, ConstructorResolver would reject any candidate if the
parameter is `null`. The reason for that is that null does not carry
any type and the matching algorithm would systematically fail for that
argument.

This commit adds an extra check, and several tests, to validate that
a null value is taken into account.

Closes gh-31495
This commit is contained in:
Stéphane Nicoll 2023-10-25 17:12:53 +02:00
parent fe7b6ddf88
commit 4977ef9cea
2 changed files with 48 additions and 1 deletions

View File

@ -1200,7 +1200,8 @@ class ConstructorResolver {
}
private Predicate<ResolvableType> isAssignable(ResolvableType valueType) {
return parameterType -> parameterType.isAssignableFrom(valueType);
return parameterType -> (valueType == ResolvableType.NONE
|| parameterType.isAssignableFrom(valueType));
}
private ResolvableType extractElementType(ResolvableType parameterType) {

View File

@ -414,6 +414,43 @@ class ConstructorResolverAotTests {
String[].class));
}
@Test
void beanDefinitionWithMultiConstructorSimilarArgumentsAndMatchingValues() throws NoSuchMethodException {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
BeanDefinition beanDefinition = BeanDefinitionBuilder
.rootBeanDefinition(MultiConstructorSimilarArgumentsSample.class)
.addConstructorArgValue("Test").addConstructorArgValue(1).addConstructorArgValue(2)
.getBeanDefinition();
Executable executable = resolve(beanFactory, beanDefinition);
assertThat(executable).isNotNull()
.isEqualTo(MultiConstructorSimilarArgumentsSample.class
.getDeclaredConstructor(String.class, Integer.class, Integer.class));
}
@Test
void beanDefinitionWithMultiConstructorSimilarArgumentsAndNullValueForCommonArgument() throws NoSuchMethodException {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
BeanDefinition beanDefinition = BeanDefinitionBuilder
.rootBeanDefinition(MultiConstructorSimilarArgumentsSample.class)
.addConstructorArgValue(null).addConstructorArgValue(null).addConstructorArgValue("Test")
.getBeanDefinition();
Executable executable = resolve(beanFactory, beanDefinition);
assertThat(executable).isNotNull()
.isEqualTo(MultiConstructorSimilarArgumentsSample.class
.getDeclaredConstructor(String.class, Integer.class, String.class));
}
@Test
void beanDefinitionWithMultiConstructorSimilarArgumentsAndNullValueForSpecificArgument() throws NoSuchMethodException {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
BeanDefinition beanDefinition = BeanDefinitionBuilder
.rootBeanDefinition(MultiConstructorSimilarArgumentsSample.class)
.addConstructorArgValue(null).addConstructorArgValue(1).addConstructorArgValue(null)
.getBeanDefinition();
assertThatIllegalStateException().isThrownBy(() -> resolve(beanFactory, beanDefinition))
.withMessageContaining(MultiConstructorSimilarArgumentsSample.class.getName());
}
@Test
void beanDefinitionWithMultiArgConstructorAndPrimitiveConversion() throws NoSuchMethodException {
BeanDefinition beanDefinition = BeanDefinitionBuilder
@ -534,6 +571,15 @@ class ConstructorResolverAotTests {
}
}
static class MultiConstructorSimilarArgumentsSample {
MultiConstructorSimilarArgumentsSample(String name, Integer counter, String value) {
}
MultiConstructorSimilarArgumentsSample(String name, Integer counter, Integer value) {
}
}
@SuppressWarnings("unused")
static class ClassArrayFactoryMethodSample {