diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java
index a33ed6589e..cfe37ae988 100644
--- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java
+++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java
@@ -220,7 +220,8 @@ class ConstructorResolver {
args = new ArgumentsHolder(explicitArgs);
}
- int typeDiffWeight = args.getTypeDifferenceWeight(paramTypes);
+ int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
+ args.getTypeDifferenceWeight(paramTypes) : args.getAssignabilityWeight(paramTypes));
// Choose this constructor if it represents the closest match.
if (typeDiffWeight < minTypeDiffWeight) {
constructorToUse = candidate;
@@ -436,8 +437,9 @@ class ConstructorResolver {
args = new ArgumentsHolder(explicitArgs);
}
- int typeDiffWeight = args.getTypeDifferenceWeight(paramTypes);
- // Choose this constructor if it represents the closest match.
+ int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
+ args.getTypeDifferenceWeight(paramTypes) : args.getAssignabilityWeight(paramTypes));
+ // Choose this factory method if it represents the closest match.
if (typeDiffWeight < minTypeDiffWeight) {
factoryMethodToUse = candidate;
argsToUse = args.arguments;
@@ -744,6 +746,20 @@ class ConstructorResolver {
int rawTypeDiffWeight = MethodInvoker.getTypeDifferenceWeight(paramTypes, this.rawArguments) - 1024;
return (rawTypeDiffWeight < typeDiffWeight ? rawTypeDiffWeight : typeDiffWeight);
}
+
+ public int getAssignabilityWeight(Class[] paramTypes) {
+ for (int i = 0; i < paramTypes.length; i++) {
+ if (!ClassUtils.isAssignableValue(paramTypes[i], this.arguments[i])) {
+ return Integer.MAX_VALUE;
+ }
+ }
+ for (int i = 0; i < paramTypes.length; i++) {
+ if (!ClassUtils.isAssignableValue(paramTypes[i], this.rawArguments[i])) {
+ return Integer.MAX_VALUE - 512;
+ }
+ }
+ return Integer.MAX_VALUE - 1024;
+ }
}
diff --git a/org.springframework.context/src/test/java/org/springframework/beans/factory/xml/XmlBeanFactoryTests-constructorArg.xml b/org.springframework.context/src/test/java/org/springframework/beans/factory/xml/XmlBeanFactoryTests-constructorArg.xml
index 1c05a0e6b0..af32261b91 100644
--- a/org.springframework.context/src/test/java/org/springframework/beans/factory/xml/XmlBeanFactoryTests-constructorArg.xml
+++ b/org.springframework.context/src/test/java/org/springframework/beans/factory/xml/XmlBeanFactoryTests-constructorArg.xml
@@ -180,6 +180,18 @@
true
+
+
+
+
+
+
+
+
+
+
+
+
test
diff --git a/org.springframework.context/src/test/java/org/springframework/beans/factory/xml/XmlBeanFactoryTests.java b/org.springframework.context/src/test/java/org/springframework/beans/factory/xml/XmlBeanFactoryTests.java
index 5a33d8c8e2..9f8e293bc0 100644
--- a/org.springframework.context/src/test/java/org/springframework/beans/factory/xml/XmlBeanFactoryTests.java
+++ b/org.springframework.context/src/test/java/org/springframework/beans/factory/xml/XmlBeanFactoryTests.java
@@ -1395,6 +1395,48 @@ public final class XmlBeanFactoryTests {
}
}
+ public @Test void testLenientDependencyMatching() {
+ XmlBeanFactory xbf = new XmlBeanFactory(CONSTRUCTOR_ARG_CONTEXT);
+ LenientDependencyTestBean bean = (LenientDependencyTestBean) xbf.getBean("lenientDependencyTestBean");
+ assertTrue(bean.tb instanceof DerivedTestBean);
+ }
+
+ public @Test void testLenientDependencyMatchingFactoryMethod() {
+ XmlBeanFactory xbf = new XmlBeanFactory(CONSTRUCTOR_ARG_CONTEXT);
+ LenientDependencyTestBean bean = (LenientDependencyTestBean) xbf.getBean("lenientDependencyTestBeanFactoryMethod");
+ assertTrue(bean.tb instanceof DerivedTestBean);
+ }
+
+ public @Test void testNonLenientDependencyMatching() {
+ XmlBeanFactory xbf = new XmlBeanFactory(CONSTRUCTOR_ARG_CONTEXT);
+ AbstractBeanDefinition bd = (AbstractBeanDefinition) xbf.getBeanDefinition("lenientDependencyTestBean");
+ bd.setLenientConstructorResolution(false);
+ try {
+ xbf.getBean("lenientDependencyTestBean");
+ fail("Should have thrown BeanCreationException");
+ }
+ catch (BeanCreationException ex) {
+ // expected
+ ex.printStackTrace();
+ assertTrue(ex.getMostSpecificCause().getMessage().contains("Ambiguous"));
+ }
+ }
+
+ public @Test void testNonLenientDependencyMatchingFactoryMethod() {
+ XmlBeanFactory xbf = new XmlBeanFactory(CONSTRUCTOR_ARG_CONTEXT);
+ AbstractBeanDefinition bd = (AbstractBeanDefinition) xbf.getBeanDefinition("lenientDependencyTestBeanFactoryMethod");
+ bd.setLenientConstructorResolution(false);
+ try {
+ xbf.getBean("lenientDependencyTestBeanFactoryMethod");
+ fail("Should have thrown BeanCreationException");
+ }
+ catch (BeanCreationException ex) {
+ // expected
+ ex.printStackTrace();
+ assertTrue(ex.getMostSpecificCause().getMessage().contains("Ambiguous"));
+ }
+ }
+
public @Test void testStringConstructor() {
XmlBeanFactory xbf = new XmlBeanFactory(CONSTRUCTOR_ARG_CONTEXT);
AbstractBeanDefinition bd = (AbstractBeanDefinition) xbf.getBeanDefinition("string");
@@ -1425,7 +1467,7 @@ public final class XmlBeanFactoryTests {
fail("Duplicate name not detected");
}
catch (BeansException ex) {
- assertTrue(ex.getMessage().indexOf("Bean name 'foo'") > -1);
+ assertTrue(ex.getMessage().contains("Bean name 'foo'"));
}
}
@@ -1435,7 +1477,7 @@ public final class XmlBeanFactoryTests {
fail("Duplicate name not detected");
}
catch (BeansException e) {
- assertTrue(e.getMessage().indexOf("Bean name 'foo'") > -1);
+ assertTrue(e.getMessage().contains("Bean name 'foo'"));
}
}
@@ -1658,6 +1700,40 @@ public final class XmlBeanFactoryTests {
}
+ public static class LenientDependencyTestBean {
+
+ public final ITestBean tb;
+
+ public LenientDependencyTestBean(ITestBean tb) {
+ this.tb = tb;
+ }
+
+ public LenientDependencyTestBean(TestBean tb) {
+ this.tb = tb;
+ }
+
+ public LenientDependencyTestBean(DerivedTestBean tb) {
+ this.tb = tb;
+ }
+
+ public LenientDependencyTestBean(Map[] m) {
+ throw new IllegalStateException("Don't pick this constructor");
+ }
+
+ public static LenientDependencyTestBean create(ITestBean tb) {
+ return new LenientDependencyTestBean(tb);
+ }
+
+ public static LenientDependencyTestBean create(TestBean tb) {
+ return new LenientDependencyTestBean(tb);
+ }
+
+ public static LenientDependencyTestBean create(DerivedTestBean tb) {
+ return new LenientDependencyTestBean(tb);
+ }
+ }
+
+
public static class ConstructorArrayTestBean {
public final Object array;