Skip to content

Commit 666700f

Browse files
committed
constructor arguments can be overridden by name in child bean definitions (SPR-6463)
1 parent cc32399 commit 666700f

File tree

3 files changed

+50
-17
lines changed

3 files changed

+50
-17
lines changed

org.springframework.beans/src/main/java/org/springframework/beans/factory/config/ConstructorArgumentValues.java

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -76,15 +76,15 @@ public void addArgumentValues(ConstructorArgumentValues other) {
7676
}
7777
for (ValueHolder valueHolder : other.genericArgumentValues) {
7878
if (!this.genericArgumentValues.contains(valueHolder)) {
79-
this.genericArgumentValues.add(valueHolder.copy());
79+
addOrMergeGenericArgumentValue(valueHolder.copy());
8080
}
8181
}
8282
}
8383
}
8484

8585

8686
/**
87-
* Add argument value for the given index in the constructor argument list.
87+
* Add an argument value for the given index in the constructor argument list.
8888
* @param index the index in the constructor argument list
8989
* @param value the argument value
9090
*/
@@ -93,7 +93,7 @@ public void addIndexedArgumentValue(int index, Object value) {
9393
}
9494

9595
/**
96-
* Add argument value for the given index in the constructor argument list.
96+
* Add an argument value for the given index in the constructor argument list.
9797
* @param index the index in the constructor argument list
9898
* @param value the argument value
9999
* @param type the type of the constructor argument
@@ -103,7 +103,7 @@ public void addIndexedArgumentValue(int index, Object value, String type) {
103103
}
104104

105105
/**
106-
* Add argument value for the given index in the constructor argument list.
106+
* Add an argument value for the given index in the constructor argument list.
107107
* @param index the index in the constructor argument list
108108
* @param newValue the argument value in the form of a ValueHolder
109109
*/
@@ -114,7 +114,7 @@ public void addIndexedArgumentValue(int index, ValueHolder newValue) {
114114
}
115115

116116
/**
117-
* Add argument value for the given index in the constructor argument list,
117+
* Add an argument value for the given index in the constructor argument list,
118118
* merging the new value (typically a collection) with the current value
119119
* if demanded: see {@link org.springframework.beans.Mergeable}.
120120
* @param key the index in the constructor argument list
@@ -183,7 +183,7 @@ public Map<Integer, ValueHolder> getIndexedArgumentValues() {
183183

184184

185185
/**
186-
* Add generic argument value to be matched by type.
186+
* Add a generic argument value to be matched by type.
187187
* <p>Note: A single generic argument value will just be used once,
188188
* rather than matched multiple times.
189189
* @param value the argument value
@@ -193,7 +193,7 @@ public void addGenericArgumentValue(Object value) {
193193
}
194194

195195
/**
196-
* Add generic argument value to be matched by type.
196+
* Add a generic argument value to be matched by type.
197197
* <p>Note: A single generic argument value will just be used once,
198198
* rather than matched multiple times.
199199
* @param value the argument value
@@ -204,7 +204,7 @@ public void addGenericArgumentValue(Object value, String type) {
204204
}
205205

206206
/**
207-
* Add generic argument value to be matched by type.
207+
* Add a generic argument value to be matched by type or name (if available).
208208
* <p>Note: A single generic argument value will just be used once,
209209
* rather than matched multiple times.
210210
* @param newValue the argument value in the form of a ValueHolder
@@ -215,10 +215,33 @@ public void addGenericArgumentValue(Object value, String type) {
215215
public void addGenericArgumentValue(ValueHolder newValue) {
216216
Assert.notNull(newValue, "ValueHolder must not be null");
217217
if (!this.genericArgumentValues.contains(newValue)) {
218-
this.genericArgumentValues.add(newValue);
218+
addOrMergeGenericArgumentValue(newValue);
219219
}
220220
}
221221

222+
/**
223+
* Add a generic argument value, merging the new value (typically a collection)
224+
* with the current value if demanded: see {@link org.springframework.beans.Mergeable}.
225+
* @param newValue the argument value in the form of a ValueHolder
226+
*/
227+
private void addOrMergeGenericArgumentValue(ValueHolder newValue) {
228+
if (newValue.getName() != null) {
229+
for (Iterator<ValueHolder> it = this.genericArgumentValues.iterator(); it.hasNext();) {
230+
ValueHolder currentValue = it.next();
231+
if (newValue.getName().equals(currentValue.getName())) {
232+
if (newValue.getValue() instanceof Mergeable) {
233+
Mergeable mergeable = (Mergeable) newValue.getValue();
234+
if (mergeable.isMergeEnabled()) {
235+
newValue.setValue(mergeable.merge(currentValue.getValue()));
236+
}
237+
}
238+
it.remove();
239+
}
240+
}
241+
}
242+
this.genericArgumentValues.add(newValue);
243+
}
244+
222245
/**
223246
* Look for a generic argument value that matches the given type.
224247
* @param requiredType the type to match
@@ -244,8 +267,8 @@ public ValueHolder getGenericArgumentValue(Class requiredType, String requiredNa
244267
* resolution process.
245268
* @param requiredType the type to match (can be <code>null</code> to find
246269
* an arbitrary next generic argument value)
247-
* @param requiredName the type to match (can be <code>null</code> to match
248-
* unnamed values only)
270+
* @param requiredName the name to match (can be <code>null</code> to not
271+
* match argument values by name)
249272
* @param usedValueHolders a Set of ValueHolder objects that have already been used
250273
* in the current resolution process and should therefore not be returned again
251274
* @return the ValueHolder for the argument, or <code>null</code> if none found

org.springframework.context/src/test/java/org/springframework/beans/factory/xml/XmlBeanFactoryTests-constructorArg.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,12 @@
109109
<constructor-arg><value>29</value></constructor-arg>
110110
</bean>
111111

112-
<bean id="rod17" class="org.springframework.beans.factory.xml.SimpleConstructorArgBean" scope="prototype">
112+
<bean id="rod17" parent="rod16">
113+
<constructor-arg name="otherSpouse"><ref bean="kerry2"/></constructor-arg>
114+
<constructor-arg name="spouse"><ref bean="kerry1"/></constructor-arg>
115+
</bean>
116+
117+
<bean id="rod18" class="org.springframework.beans.factory.xml.SimpleConstructorArgBean" scope="prototype">
113118
</bean>
114119

115120
<bean id="kerry1" class="org.springframework.beans.TestBean">

org.springframework.context/src/test/java/org/springframework/beans/factory/xml/XmlBeanFactoryTests.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -955,19 +955,24 @@ private void doTestAutowire(XmlBeanFactory xbf) throws Exception {
955955
assertEquals(kerry2, rod16.getSpouse1());
956956
assertEquals(kerry1, rod16.getSpouse2());
957957
assertEquals(29, rod16.getAge());
958+
959+
ConstructorDependenciesBean rod17 = (ConstructorDependenciesBean) xbf.getBean("rod17");
960+
assertEquals(kerry1, rod17.getSpouse1());
961+
assertEquals(kerry2, rod17.getSpouse2());
962+
assertEquals(29, rod17.getAge());
958963
}
959964

960965
public @Test void testPrototypeWithExplicitArguments() {
961966
XmlBeanFactory xbf = new XmlBeanFactory(CONSTRUCTOR_ARG_CONTEXT);
962-
SimpleConstructorArgBean cd1 = (SimpleConstructorArgBean) xbf.getBean("rod17");
967+
SimpleConstructorArgBean cd1 = (SimpleConstructorArgBean) xbf.getBean("rod18");
963968
assertEquals(0, cd1.getAge());
964-
SimpleConstructorArgBean cd2 = (SimpleConstructorArgBean) xbf.getBean("rod17", 98);
969+
SimpleConstructorArgBean cd2 = (SimpleConstructorArgBean) xbf.getBean("rod18", 98);
965970
assertEquals(98, cd2.getAge());
966-
SimpleConstructorArgBean cd3 = (SimpleConstructorArgBean) xbf.getBean("rod17", "myName");
971+
SimpleConstructorArgBean cd3 = (SimpleConstructorArgBean) xbf.getBean("rod18", "myName");
967972
assertEquals("myName", cd3.getName());
968-
SimpleConstructorArgBean cd4 = (SimpleConstructorArgBean) xbf.getBean("rod17");
973+
SimpleConstructorArgBean cd4 = (SimpleConstructorArgBean) xbf.getBean("rod18");
969974
assertEquals(0, cd4.getAge());
970-
SimpleConstructorArgBean cd5 = (SimpleConstructorArgBean) xbf.getBean("rod17", 97);
975+
SimpleConstructorArgBean cd5 = (SimpleConstructorArgBean) xbf.getBean("rod18", 97);
971976
assertEquals(97, cd5.getAge());
972977
}
973978

0 commit comments

Comments
 (0)