introduced "lenientConstructorResolution" flag (SPR-5816)
This commit is contained in:
parent
f4a83c5c74
commit
a9254b34d1
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.beans.factory.support;
|
package org.springframework.beans.factory.support;
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
|
@ -144,6 +143,8 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||||
|
|
||||||
private ConstructorArgumentValues constructorArgumentValues;
|
private ConstructorArgumentValues constructorArgumentValues;
|
||||||
|
|
||||||
|
private boolean lenientConstructorResolution = true;
|
||||||
|
|
||||||
private MutablePropertyValues propertyValues;
|
private MutablePropertyValues propertyValues;
|
||||||
|
|
||||||
private MethodOverrides methodOverrides = new MethodOverrides();
|
private MethodOverrides methodOverrides = new MethodOverrides();
|
||||||
|
|
@ -168,7 +169,6 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||||
|
|
||||||
private Resource resource;
|
private Resource resource;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new AbstractBeanDefinition with default settings.
|
* Create a new AbstractBeanDefinition with default settings.
|
||||||
*/
|
*/
|
||||||
|
|
@ -226,6 +226,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||||
setAutowireCandidate(originalAbd.isAutowireCandidate());
|
setAutowireCandidate(originalAbd.isAutowireCandidate());
|
||||||
copyQualifiersFrom(originalAbd);
|
copyQualifiersFrom(originalAbd);
|
||||||
setPrimary(originalAbd.isPrimary());
|
setPrimary(originalAbd.isPrimary());
|
||||||
|
setLenientConstructorResolution(originalAbd.isLenientConstructorResolution());
|
||||||
setInitMethodName(originalAbd.getInitMethodName());
|
setInitMethodName(originalAbd.getInitMethodName());
|
||||||
setEnforceInitMethod(originalAbd.isEnforceInitMethod());
|
setEnforceInitMethod(originalAbd.isEnforceInitMethod());
|
||||||
setDestroyMethodName(originalAbd.getDestroyMethodName());
|
setDestroyMethodName(originalAbd.getDestroyMethodName());
|
||||||
|
|
@ -297,6 +298,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||||
setPrimary(otherAbd.isPrimary());
|
setPrimary(otherAbd.isPrimary());
|
||||||
setDependencyCheck(otherAbd.getDependencyCheck());
|
setDependencyCheck(otherAbd.getDependencyCheck());
|
||||||
setDependsOn(otherAbd.getDependsOn());
|
setDependsOn(otherAbd.getDependsOn());
|
||||||
|
setLenientConstructorResolution(otherAbd.isLenientConstructorResolution());
|
||||||
if (otherAbd.getInitMethodName() != null) {
|
if (otherAbd.getInitMethodName() != null) {
|
||||||
setInitMethodName(otherAbd.getInitMethodName());
|
setInitMethodName(otherAbd.getInitMethodName());
|
||||||
setEnforceInitMethod(otherAbd.isEnforceInitMethod());
|
setEnforceInitMethod(otherAbd.isEnforceInitMethod());
|
||||||
|
|
@ -642,7 +644,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||||
* Copy the qualifiers from the supplied AbstractBeanDefinition to this bean definition.
|
* Copy the qualifiers from the supplied AbstractBeanDefinition to this bean definition.
|
||||||
* @param source the AbstractBeanDefinition to copy from
|
* @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");
|
Assert.notNull(source, "Source must not be null");
|
||||||
this.qualifiers.putAll(source.qualifiers);
|
this.qualifiers.putAll(source.qualifiers);
|
||||||
}
|
}
|
||||||
|
|
@ -670,6 +672,23 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
|
||||||
return !this.constructorArgumentValues.isEmpty();
|
return !this.constructorArgumentValues.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify whether to resolve constructors in lenient mode (<code>true</code>,
|
||||||
|
* 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.
|
* Specify property values for this bean, if any.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -226,6 +226,12 @@ class ConstructorResolver {
|
||||||
argsToUse = args.arguments;
|
argsToUse = args.arguments;
|
||||||
minTypeDiffWeight = typeDiffWeight;
|
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) {
|
if (constructorToUse == null) {
|
||||||
|
|
@ -561,21 +567,24 @@ class ConstructorResolver {
|
||||||
// We found a potential match - let's give it a try.
|
// We found a potential match - let's give it a try.
|
||||||
// Do not consider the same value definition multiple times!
|
// Do not consider the same value definition multiple times!
|
||||||
usedValueHolders.add(valueHolder);
|
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()) {
|
if (valueHolder.isConverted()) {
|
||||||
Object convertedValue = valueHolder.getConvertedValue();
|
Object convertedValue = valueHolder.getConvertedValue();
|
||||||
|
args.rawArguments[paramIndex] =
|
||||||
|
(mbd.isLenientConstructorResolution() ? originalValue : convertedValue);
|
||||||
args.arguments[paramIndex] = convertedValue;
|
args.arguments[paramIndex] = convertedValue;
|
||||||
args.preparedArguments[paramIndex] = convertedValue;
|
args.preparedArguments[paramIndex] = convertedValue;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
try {
|
try {
|
||||||
Object originalValue = valueHolder.getValue();
|
|
||||||
Object convertedValue = converter.convertIfNecessary(originalValue, paramType,
|
Object convertedValue = converter.convertIfNecessary(originalValue, paramType,
|
||||||
MethodParameter.forMethodOrConstructor(methodOrCtor, paramIndex));
|
MethodParameter.forMethodOrConstructor(methodOrCtor, paramIndex));
|
||||||
|
args.rawArguments[paramIndex] =
|
||||||
|
(mbd.isLenientConstructorResolution() ? originalValue : convertedValue);
|
||||||
args.arguments[paramIndex] = convertedValue;
|
args.arguments[paramIndex] = convertedValue;
|
||||||
ConstructorArgumentValues.ValueHolder sourceHolder =
|
|
||||||
(ConstructorArgumentValues.ValueHolder) valueHolder.getSource();
|
|
||||||
Object sourceValue = sourceHolder.getValue();
|
|
||||||
if (originalValue == sourceValue || sourceValue instanceof TypedStringValue) {
|
if (originalValue == sourceValue || sourceValue instanceof TypedStringValue) {
|
||||||
// Either a converted value or still the original one: store converted value.
|
// Either a converted value or still the original one: store converted value.
|
||||||
sourceHolder.setConvertedValue(convertedValue);
|
sourceHolder.setConvertedValue(convertedValue);
|
||||||
|
|
|
||||||
|
|
@ -170,6 +170,11 @@
|
||||||
<constructor-arg index="1"><value>true</value></constructor-arg>
|
<constructor-arg index="1"><value>true</value></constructor-arg>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<bean id="beanWithDoubleBooleanNoType" class="org.springframework.beans.factory.xml.XmlBeanFactoryTests$DoubleBooleanConstructorBean" scope="prototype">
|
||||||
|
<constructor-arg index="0"><value>false</value></constructor-arg>
|
||||||
|
<constructor-arg index="1"><value>true</value></constructor-arg>
|
||||||
|
</bean>
|
||||||
|
|
||||||
<bean id="constructorArray" class="org.springframework.beans.factory.xml.XmlBeanFactoryTests$ConstructorArrayTestBean">
|
<bean id="constructorArray" class="org.springframework.beans.factory.xml.XmlBeanFactoryTests$ConstructorArrayTestBean">
|
||||||
<constructor-arg type="int[]">
|
<constructor-arg type="int[]">
|
||||||
<array value-type="int">
|
<array value-type="int">
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
import org.springframework.beans.factory.support.MethodReplacer;
|
import org.springframework.beans.factory.support.MethodReplacer;
|
||||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
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.ClassPathResource;
|
||||||
import org.springframework.core.io.FileSystemResource;
|
import org.springframework.core.io.FileSystemResource;
|
||||||
import org.springframework.core.io.UrlResource;
|
import org.springframework.core.io.UrlResource;
|
||||||
|
|
@ -1363,6 +1364,21 @@ public final class XmlBeanFactoryTests {
|
||||||
assertEquals(Boolean.TRUE, bean.boolean2);
|
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() {
|
public @Test void testPrimitiveConstructorArray() {
|
||||||
XmlBeanFactory xbf = new XmlBeanFactory(CONSTRUCTOR_ARG_CONTEXT);
|
XmlBeanFactory xbf = new XmlBeanFactory(CONSTRUCTOR_ARG_CONTEXT);
|
||||||
ConstructorArrayTestBean bean = (ConstructorArrayTestBean) xbf.getBean("constructorArray");
|
ConstructorArrayTestBean bean = (ConstructorArrayTestBean) xbf.getBean("constructorArray");
|
||||||
|
|
@ -1603,6 +1619,10 @@ public final class XmlBeanFactoryTests {
|
||||||
this.boolean1 = b1;
|
this.boolean1 = b1;
|
||||||
this.boolean2 = b2;
|
this.boolean2 = b2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DoubleBooleanConstructorBean(String s1, String s2) {
|
||||||
|
throw new IllegalStateException("Don't pick this constructor");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue