diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinition.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinition.java
index b0fdd5320ad..0dc8f487091 100644
--- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinition.java
+++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinition.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2008 the original author or authors.
+ * Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,7 +16,6 @@
package org.springframework.beans.factory.support;
-import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.util.Arrays;
import java.util.LinkedHashMap;
@@ -144,6 +143,8 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
private ConstructorArgumentValues constructorArgumentValues;
+ private boolean lenientConstructorResolution = true;
+
private MutablePropertyValues propertyValues;
private MethodOverrides methodOverrides = new MethodOverrides();
@@ -168,7 +169,6 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
private Resource resource;
-
/**
* Create a new AbstractBeanDefinition with default settings.
*/
@@ -226,6 +226,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
setAutowireCandidate(originalAbd.isAutowireCandidate());
copyQualifiersFrom(originalAbd);
setPrimary(originalAbd.isPrimary());
+ setLenientConstructorResolution(originalAbd.isLenientConstructorResolution());
setInitMethodName(originalAbd.getInitMethodName());
setEnforceInitMethod(originalAbd.isEnforceInitMethod());
setDestroyMethodName(originalAbd.getDestroyMethodName());
@@ -297,6 +298,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
setPrimary(otherAbd.isPrimary());
setDependencyCheck(otherAbd.getDependencyCheck());
setDependsOn(otherAbd.getDependsOn());
+ setLenientConstructorResolution(otherAbd.isLenientConstructorResolution());
if (otherAbd.getInitMethodName() != null) {
setInitMethodName(otherAbd.getInitMethodName());
setEnforceInitMethod(otherAbd.isEnforceInitMethod());
@@ -642,7 +644,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
* Copy the qualifiers from the supplied AbstractBeanDefinition to this bean definition.
* @param source the AbstractBeanDefinition to copy from
*/
- protected void copyQualifiersFrom(AbstractBeanDefinition source) {
+ public void copyQualifiersFrom(AbstractBeanDefinition source) {
Assert.notNull(source, "Source must not be null");
this.qualifiers.putAll(source.qualifiers);
}
@@ -670,6 +672,23 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
return !this.constructorArgumentValues.isEmpty();
}
+ /**
+ * Specify whether to resolve constructors in lenient mode (true,
+ * which is the default) or to switch to strict resolution (throwing an exception
+ * in case of ambigious constructors that all match when converting the arguments,
+ * whereas lenient mode would use the one with the 'closest' type matches).
+ */
+ public void setLenientConstructorResolution(boolean lenientConstructorResolution) {
+ this.lenientConstructorResolution = lenientConstructorResolution;
+ }
+
+ /**
+ * Return whether to resolve constructors in lenient mode or in strict mode.
+ */
+ public boolean isLenientConstructorResolution() {
+ return this.lenientConstructorResolution;
+ }
+
/**
* Specify property values for this bean, if any.
*/
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 86c3bd3f006..6972e847b79 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
@@ -226,6 +226,12 @@ class ConstructorResolver {
argsToUse = args.arguments;
minTypeDiffWeight = typeDiffWeight;
}
+ else if (typeDiffWeight < Integer.MAX_VALUE && typeDiffWeight == minTypeDiffWeight &&
+ !mbd.isLenientConstructorResolution()) {
+ throw new BeanCreationException(mbd.getResourceDescription(), beanName,
+ "Ambiguous constructor matches found in bean '" + beanName + "' " +
+ "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
+ }
}
if (constructorToUse == null) {
@@ -561,21 +567,24 @@ class ConstructorResolver {
// We found a potential match - let's give it a try.
// Do not consider the same value definition multiple times!
usedValueHolders.add(valueHolder);
- args.rawArguments[paramIndex] = valueHolder.getValue();
+ ConstructorArgumentValues.ValueHolder sourceHolder =
+ (ConstructorArgumentValues.ValueHolder) valueHolder.getSource();
+ Object originalValue = valueHolder.getValue();
+ Object sourceValue = sourceHolder.getValue();
if (valueHolder.isConverted()) {
Object convertedValue = valueHolder.getConvertedValue();
+ args.rawArguments[paramIndex] =
+ (mbd.isLenientConstructorResolution() ? originalValue : convertedValue);
args.arguments[paramIndex] = convertedValue;
args.preparedArguments[paramIndex] = convertedValue;
}
else {
try {
- Object originalValue = valueHolder.getValue();
Object convertedValue = converter.convertIfNecessary(originalValue, paramType,
MethodParameter.forMethodOrConstructor(methodOrCtor, paramIndex));
+ args.rawArguments[paramIndex] =
+ (mbd.isLenientConstructorResolution() ? originalValue : convertedValue);
args.arguments[paramIndex] = convertedValue;
- ConstructorArgumentValues.ValueHolder sourceHolder =
- (ConstructorArgumentValues.ValueHolder) valueHolder.getSource();
- Object sourceValue = sourceHolder.getValue();
if (originalValue == sourceValue || sourceValue instanceof TypedStringValue) {
// Either a converted value or still the original one: store converted value.
sourceHolder.setConvertedValue(convertedValue);
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 c61eb498015..e12640a6faa 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
@@ -170,6 +170,11 @@
true
+
+ false
+ true
+
+
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 9162d47c8b9..633be540d6d 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
@@ -56,6 +56,7 @@ import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.MethodReplacer;
import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.UrlResource;
@@ -1363,6 +1364,21 @@ public final class XmlBeanFactoryTests {
assertEquals(Boolean.TRUE, bean.boolean2);
}
+ public @Test void testDoubleBooleanNoType() {
+ XmlBeanFactory xbf = new XmlBeanFactory(CONSTRUCTOR_ARG_CONTEXT);
+ AbstractBeanDefinition bd = (AbstractBeanDefinition) xbf.getBeanDefinition("beanWithDoubleBooleanNoType");
+ bd.setLenientConstructorResolution(false);
+ try {
+ xbf.getBean("beanWithDoubleBooleanNoType");
+ fail("Should have thrown BeanCreationException");
+ }
+ catch (BeanCreationException ex) {
+ // expected
+ ex.printStackTrace();
+ assertTrue(ex.getMostSpecificCause().getMessage().contains("Ambiguous"));
+ }
+ }
+
public @Test void testPrimitiveConstructorArray() {
XmlBeanFactory xbf = new XmlBeanFactory(CONSTRUCTOR_ARG_CONTEXT);
ConstructorArrayTestBean bean = (ConstructorArrayTestBean) xbf.getBean("constructorArray");
@@ -1603,6 +1619,10 @@ public final class XmlBeanFactoryTests {
this.boolean1 = b1;
this.boolean2 = b2;
}
+
+ public DoubleBooleanConstructorBean(String s1, String s2) {
+ throw new IllegalStateException("Don't pick this constructor");
+ }
}