From 4977ef9cea8c34337dd9cc87055d1efd56dea8a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Wed, 25 Oct 2023 17:12:53 +0200 Subject: [PATCH] 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 --- .../factory/support/ConstructorResolver.java | 3 +- .../support/ConstructorResolverAotTests.java | 46 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java index c4ecb81c6a..26bc22becb 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java @@ -1200,7 +1200,8 @@ class ConstructorResolver { } private Predicate isAssignable(ResolvableType valueType) { - return parameterType -> parameterType.isAssignableFrom(valueType); + return parameterType -> (valueType == ResolvableType.NONE + || parameterType.isAssignableFrom(valueType)); } private ResolvableType extractElementType(ResolvableType parameterType) { diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/support/ConstructorResolverAotTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/support/ConstructorResolverAotTests.java index 81b7ca8799..434a232b46 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/support/ConstructorResolverAotTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/support/ConstructorResolverAotTests.java @@ -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 {