From 65df1c6f4c048f13ab4b1a9bd085c5a8da321aa6 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Mon, 30 Nov 2009 12:17:28 +0000 Subject: [PATCH] constructor arguments can be overridden by name in child bean definitions (SPR-6463) git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@2546 50f2f4bb-b051-0410-bef5-90022cba6387 --- .../config/ConstructorArgumentValues.java | 45 ++++++++++++++----- .../XmlBeanFactoryTests-constructorArg.xml | 7 ++- .../factory/xml/XmlBeanFactoryTests.java | 15 ++++--- 3 files changed, 50 insertions(+), 17 deletions(-) diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/ConstructorArgumentValues.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/ConstructorArgumentValues.java index f71eb5d178f..a0701c2558d 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/ConstructorArgumentValues.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/ConstructorArgumentValues.java @@ -76,7 +76,7 @@ public class ConstructorArgumentValues { } for (ValueHolder valueHolder : other.genericArgumentValues) { if (!this.genericArgumentValues.contains(valueHolder)) { - this.genericArgumentValues.add(valueHolder.copy()); + addOrMergeGenericArgumentValue(valueHolder.copy()); } } } @@ -84,7 +84,7 @@ public class ConstructorArgumentValues { /** - * Add argument value for the given index in the constructor argument list. + * Add an argument value for the given index in the constructor argument list. * @param index the index in the constructor argument list * @param value the argument value */ @@ -93,7 +93,7 @@ public class ConstructorArgumentValues { } /** - * Add argument value for the given index in the constructor argument list. + * Add an argument value for the given index in the constructor argument list. * @param index the index in the constructor argument list * @param value the argument value * @param type the type of the constructor argument @@ -103,7 +103,7 @@ public class ConstructorArgumentValues { } /** - * Add argument value for the given index in the constructor argument list. + * Add an argument value for the given index in the constructor argument list. * @param index the index in the constructor argument list * @param newValue the argument value in the form of a ValueHolder */ @@ -114,7 +114,7 @@ public class ConstructorArgumentValues { } /** - * Add argument value for the given index in the constructor argument list, + * Add an argument value for the given index in the constructor argument list, * merging the new value (typically a collection) with the current value * if demanded: see {@link org.springframework.beans.Mergeable}. * @param key the index in the constructor argument list @@ -183,7 +183,7 @@ public class ConstructorArgumentValues { /** - * Add generic argument value to be matched by type. + * Add a generic argument value to be matched by type. *

Note: A single generic argument value will just be used once, * rather than matched multiple times. * @param value the argument value @@ -193,7 +193,7 @@ public class ConstructorArgumentValues { } /** - * Add generic argument value to be matched by type. + * Add a generic argument value to be matched by type. *

Note: A single generic argument value will just be used once, * rather than matched multiple times. * @param value the argument value @@ -204,7 +204,7 @@ public class ConstructorArgumentValues { } /** - * Add generic argument value to be matched by type. + * Add a generic argument value to be matched by type or name (if available). *

Note: A single generic argument value will just be used once, * rather than matched multiple times. * @param newValue the argument value in the form of a ValueHolder @@ -215,10 +215,33 @@ public class ConstructorArgumentValues { public void addGenericArgumentValue(ValueHolder newValue) { Assert.notNull(newValue, "ValueHolder must not be null"); if (!this.genericArgumentValues.contains(newValue)) { - this.genericArgumentValues.add(newValue); + addOrMergeGenericArgumentValue(newValue); } } + /** + * Add a generic argument value, merging the new value (typically a collection) + * with the current value if demanded: see {@link org.springframework.beans.Mergeable}. + * @param newValue the argument value in the form of a ValueHolder + */ + private void addOrMergeGenericArgumentValue(ValueHolder newValue) { + if (newValue.getName() != null) { + for (Iterator it = this.genericArgumentValues.iterator(); it.hasNext();) { + ValueHolder currentValue = it.next(); + if (newValue.getName().equals(currentValue.getName())) { + if (newValue.getValue() instanceof Mergeable) { + Mergeable mergeable = (Mergeable) newValue.getValue(); + if (mergeable.isMergeEnabled()) { + newValue.setValue(mergeable.merge(currentValue.getValue())); + } + } + it.remove(); + } + } + } + this.genericArgumentValues.add(newValue); + } + /** * Look for a generic argument value that matches the given type. * @param requiredType the type to match @@ -244,8 +267,8 @@ public class ConstructorArgumentValues { * resolution process. * @param requiredType the type to match (can be null to find * an arbitrary next generic argument value) - * @param requiredName the type to match (can be null to match - * unnamed values only) + * @param requiredName the name to match (can be null to not + * match argument values by name) * @param usedValueHolders a Set of ValueHolder objects that have already been used * in the current resolution process and should therefore not be returned again * @return the ValueHolder for the argument, or null if none found 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 905a4d6e016..bc4f87d63a4 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 @@ -109,7 +109,12 @@ 29 - + + + + + + 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 00591c3b501..075b554b335 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 @@ -955,19 +955,24 @@ public final class XmlBeanFactoryTests { assertEquals(kerry2, rod16.getSpouse1()); assertEquals(kerry1, rod16.getSpouse2()); assertEquals(29, rod16.getAge()); + + ConstructorDependenciesBean rod17 = (ConstructorDependenciesBean) xbf.getBean("rod17"); + assertEquals(kerry1, rod17.getSpouse1()); + assertEquals(kerry2, rod17.getSpouse2()); + assertEquals(29, rod17.getAge()); } public @Test void testPrototypeWithExplicitArguments() { XmlBeanFactory xbf = new XmlBeanFactory(CONSTRUCTOR_ARG_CONTEXT); - SimpleConstructorArgBean cd1 = (SimpleConstructorArgBean) xbf.getBean("rod17"); + SimpleConstructorArgBean cd1 = (SimpleConstructorArgBean) xbf.getBean("rod18"); assertEquals(0, cd1.getAge()); - SimpleConstructorArgBean cd2 = (SimpleConstructorArgBean) xbf.getBean("rod17", 98); + SimpleConstructorArgBean cd2 = (SimpleConstructorArgBean) xbf.getBean("rod18", 98); assertEquals(98, cd2.getAge()); - SimpleConstructorArgBean cd3 = (SimpleConstructorArgBean) xbf.getBean("rod17", "myName"); + SimpleConstructorArgBean cd3 = (SimpleConstructorArgBean) xbf.getBean("rod18", "myName"); assertEquals("myName", cd3.getName()); - SimpleConstructorArgBean cd4 = (SimpleConstructorArgBean) xbf.getBean("rod17"); + SimpleConstructorArgBean cd4 = (SimpleConstructorArgBean) xbf.getBean("rod18"); assertEquals(0, cd4.getAge()); - SimpleConstructorArgBean cd5 = (SimpleConstructorArgBean) xbf.getBean("rod17", 97); + SimpleConstructorArgBean cd5 = (SimpleConstructorArgBean) xbf.getBean("rod18", 97); assertEquals(97, cd5.getAge()); }