001/*
002 * Copyright 2002-2019 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.beans.factory.config;
018
019import java.util.Collections;
020import java.util.Iterator;
021import java.util.LinkedHashMap;
022import java.util.LinkedList;
023import java.util.List;
024import java.util.Map;
025import java.util.Set;
026
027import org.springframework.beans.BeanMetadataElement;
028import org.springframework.beans.Mergeable;
029import org.springframework.util.Assert;
030import org.springframework.util.ClassUtils;
031import org.springframework.util.ObjectUtils;
032
033/**
034 * Holder for constructor argument values, typically as part of a bean definition.
035 *
036 * <p>Supports values for a specific index in the constructor argument list
037 * as well as for generic argument matches by type.
038 *
039 * @author Juergen Hoeller
040 * @since 09.11.2003
041 * @see BeanDefinition#getConstructorArgumentValues
042 */
043public class ConstructorArgumentValues {
044
045 private final Map<Integer, ValueHolder> indexedArgumentValues = new LinkedHashMap<Integer, ValueHolder>(0);
046
047 private final List<ValueHolder> genericArgumentValues = new LinkedList<ValueHolder>();
048
049
050 /**
051 * Create a new empty ConstructorArgumentValues object.
052 */
053 public ConstructorArgumentValues() {
054 }
055
056 /**
057 * Deep copy constructor.
058 * @param original the ConstructorArgumentValues to copy
059 */
060 public ConstructorArgumentValues(ConstructorArgumentValues original) {
061 addArgumentValues(original);
062 }
063
064
065 /**
066 * Copy all given argument values into this object, using separate holder
067 * instances to keep the values independent from the original object.
068 * <p>Note: Identical ValueHolder instances will only be registered once,
069 * to allow for merging and re-merging of argument value definitions. Distinct
070 * ValueHolder instances carrying the same content are of course allowed.
071 */
072 public void addArgumentValues(ConstructorArgumentValues other) {
073 if (other != null) {
074 for (Map.Entry<Integer, ValueHolder> entry : other.indexedArgumentValues.entrySet()) {
075 addOrMergeIndexedArgumentValue(entry.getKey(), entry.getValue().copy());
076 }
077 for (ValueHolder valueHolder : other.genericArgumentValues) {
078 if (!this.genericArgumentValues.contains(valueHolder)) {
079 addOrMergeGenericArgumentValue(valueHolder.copy());
080 }
081 }
082 }
083 }
084
085
086 /**
087 * Add an argument value for the given index in the constructor argument list.
088 * @param index the index in the constructor argument list
089 * @param value the argument value
090 */
091 public void addIndexedArgumentValue(int index, Object value) {
092 addIndexedArgumentValue(index, new ValueHolder(value));
093 }
094
095 /**
096 * Add an argument value for the given index in the constructor argument list.
097 * @param index the index in the constructor argument list
098 * @param value the argument value
099 * @param type the type of the constructor argument
100 */
101 public void addIndexedArgumentValue(int index, Object value, String type) {
102 addIndexedArgumentValue(index, new ValueHolder(value, type));
103 }
104
105 /**
106 * Add an argument value for the given index in the constructor argument list.
107 * @param index the index in the constructor argument list
108 * @param newValue the argument value in the form of a ValueHolder
109 */
110 public void addIndexedArgumentValue(int index, ValueHolder newValue) {
111 Assert.isTrue(index >= 0, "Index must not be negative");
112 Assert.notNull(newValue, "ValueHolder must not be null");
113 addOrMergeIndexedArgumentValue(index, newValue);
114 }
115
116 /**
117 * Add an argument value for the given index in the constructor argument list,
118 * merging the new value (typically a collection) with the current value
119 * if demanded: see {@link org.springframework.beans.Mergeable}.
120 * @param key the index in the constructor argument list
121 * @param newValue the argument value in the form of a ValueHolder
122 */
123 private void addOrMergeIndexedArgumentValue(Integer key, ValueHolder newValue) {
124 ValueHolder currentValue = this.indexedArgumentValues.get(key);
125 if (currentValue != null && newValue.getValue() instanceof Mergeable) {
126 Mergeable mergeable = (Mergeable) newValue.getValue();
127 if (mergeable.isMergeEnabled()) {
128 newValue.setValue(mergeable.merge(currentValue.getValue()));
129 }
130 }
131 this.indexedArgumentValues.put(key, newValue);
132 }
133
134 /**
135 * Check whether an argument value has been registered for the given index.
136 * @param index the index in the constructor argument list
137 */
138 public boolean hasIndexedArgumentValue(int index) {
139 return this.indexedArgumentValues.containsKey(index);
140 }
141
142 /**
143 * Get argument value for the given index in the constructor argument list.
144 * @param index the index in the constructor argument list
145 * @param requiredType the type to match (can be {@code null} to match
146 * untyped values only)
147 * @return the ValueHolder for the argument, or {@code null} if none set
148 */
149 public ValueHolder getIndexedArgumentValue(int index, Class<?> requiredType) {
150 return getIndexedArgumentValue(index, requiredType, null);
151 }
152
153 /**
154 * Get argument value for the given index in the constructor argument list.
155 * @param index the index in the constructor argument list
156 * @param requiredType the type to match (can be {@code null} to match
157 * untyped values only)
158 * @param requiredName the type to match (can be {@code null} to match
159 * unnamed values only, or empty String to match any name)
160 * @return the ValueHolder for the argument, or {@code null} if none set
161 */
162 public ValueHolder getIndexedArgumentValue(int index, Class<?> requiredType, String requiredName) {
163 Assert.isTrue(index >= 0, "Index must not be negative");
164 ValueHolder valueHolder = this.indexedArgumentValues.get(index);
165 if (valueHolder != null &&
166 (valueHolder.getType() == null ||
167 (requiredType != null && ClassUtils.matchesTypeName(requiredType, valueHolder.getType()))) &&
168 (valueHolder.getName() == null || "".equals(requiredName) ||
169 (requiredName != null && requiredName.equals(valueHolder.getName())))) {
170 return valueHolder;
171 }
172 return null;
173 }
174
175 /**
176 * Return the map of indexed argument values.
177 * @return unmodifiable Map with Integer index as key and ValueHolder as value
178 * @see ValueHolder
179 */
180 public Map<Integer, ValueHolder> getIndexedArgumentValues() {
181 return Collections.unmodifiableMap(this.indexedArgumentValues);
182 }
183
184
185 /**
186 * Add a generic argument value to be matched by type.
187 * <p>Note: A single generic argument value will just be used once,
188 * rather than matched multiple times.
189 * @param value the argument value
190 */
191 public void addGenericArgumentValue(Object value) {
192 this.genericArgumentValues.add(new ValueHolder(value));
193 }
194
195 /**
196 * Add a generic argument value to be matched by type.
197 * <p>Note: A single generic argument value will just be used once,
198 * rather than matched multiple times.
199 * @param value the argument value
200 * @param type the type of the constructor argument
201 */
202 public void addGenericArgumentValue(Object value, String type) {
203 this.genericArgumentValues.add(new ValueHolder(value, type));
204 }
205
206 /**
207 * Add a generic argument value to be matched by type or name (if available).
208 * <p>Note: A single generic argument value will just be used once,
209 * rather than matched multiple times.
210 * @param newValue the argument value in the form of a ValueHolder
211 * <p>Note: Identical ValueHolder instances will only be registered once,
212 * to allow for merging and re-merging of argument value definitions. Distinct
213 * ValueHolder instances carrying the same content are of course allowed.
214 */
215 public void addGenericArgumentValue(ValueHolder newValue) {
216 Assert.notNull(newValue, "ValueHolder must not be null");
217 if (!this.genericArgumentValues.contains(newValue)) {
218 addOrMergeGenericArgumentValue(newValue);
219 }
220 }
221
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
245 /**
246 * Look for a generic argument value that matches the given type.
247 * @param requiredType the type to match
248 * @return the ValueHolder for the argument, or {@code null} if none set
249 */
250 public ValueHolder getGenericArgumentValue(Class<?> requiredType) {
251 return getGenericArgumentValue(requiredType, null, null);
252 }
253
254 /**
255 * Look for a generic argument value that matches the given type.
256 * @param requiredType the type to match
257 * @param requiredName the name to match
258 * @return the ValueHolder for the argument, or {@code null} if none set
259 */
260 public ValueHolder getGenericArgumentValue(Class<?> requiredType, String requiredName) {
261 return getGenericArgumentValue(requiredType, requiredName, null);
262 }
263
264 /**
265 * Look for the next generic argument value that matches the given type,
266 * ignoring argument values that have already been used in the current
267 * resolution process.
268 * @param requiredType the type to match (can be {@code null} to find
269 * an arbitrary next generic argument value)
270 * @param requiredName the name to match (can be {@code null} to not
271 * match argument values by name, or empty String to match any name)
272 * @param usedValueHolders a Set of ValueHolder objects that have already been used
273 * in the current resolution process and should therefore not be returned again
274 * @return the ValueHolder for the argument, or {@code null} if none found
275 */
276 public ValueHolder getGenericArgumentValue(Class<?> requiredType, String requiredName, Set<ValueHolder> usedValueHolders) {
277 for (ValueHolder valueHolder : this.genericArgumentValues) {
278 if (usedValueHolders != null && usedValueHolders.contains(valueHolder)) {
279 continue;
280 }
281 if (valueHolder.getName() != null && !"".equals(requiredName) &&
282 (requiredName == null || !valueHolder.getName().equals(requiredName))) {
283 continue;
284 }
285 if (valueHolder.getType() != null &&
286 (requiredType == null || !ClassUtils.matchesTypeName(requiredType, valueHolder.getType()))) {
287 continue;
288 }
289 if (requiredType != null && valueHolder.getType() == null && valueHolder.getName() == null &&
290 !ClassUtils.isAssignableValue(requiredType, valueHolder.getValue())) {
291 continue;
292 }
293 return valueHolder;
294 }
295 return null;
296 }
297298 /**
299 * Return the list of generic argument values.
300 * @return unmodifiable List of ValueHolders
301 * @see ValueHolder
302 */
303 public List<ValueHolder> getGenericArgumentValues() {
304 return Collections.unmodifiableList(this.genericArgumentValues);
305 }
306
307
308 /**
309 * Look for an argument value that either corresponds to the given index
310 * in the constructor argument list or generically matches by type.
311 * @param index the index in the constructor argument list
312 * @param requiredType the parameter type to match
313 * @return the ValueHolder for the argument, or {@code null} if none set
314 */
315 public ValueHolder getArgumentValue(int index, Class<?> requiredType) {
316 return getArgumentValue(index, requiredType, null, null);
317 }
318
319 /**
320 * Look for an argument value that either corresponds to the given index
321 * in the constructor argument list or generically matches by type.
322 * @param index the index in the constructor argument list
323 * @param requiredType the parameter type to match
324 * @param requiredName the parameter name to match
325 * @return the ValueHolder for the argument, or {@code null} if none set
326 */
327 public ValueHolder getArgumentValue(int index, Class<?> requiredType, String requiredName) {
328 return getArgumentValue(index, requiredType, requiredName, null);
329 }
330
331 /**
332 * Look for an argument value that either corresponds to the given index
333 * in the constructor argument list or generically matches by type.
334 * @param index the index in the constructor argument list
335 * @param requiredType the parameter type to match (can be {@code null}
336 * to find an untyped argument value)
337 * @param requiredName the parameter name to match (can be {@code null}
338 * to find an unnamed argument value, or empty String to match any name)
339 * @param usedValueHolders a Set of ValueHolder objects that have already
340 * been used in the current resolution process and should therefore not
341 * be returned again (allowing to return the next generic argument match
342 * in case of multiple generic argument values of the same type)
343 * @return the ValueHolder for the argument, or {@code null} if none set
344 */
345 public ValueHolder getArgumentValue(int index, Class<?> requiredType, String requiredName, Set<ValueHolder> usedValueHolders) {
346 Assert.isTrue(index >= 0, "Index must not be negative");
347 ValueHolder valueHolder = getIndexedArgumentValue(index, requiredType, requiredName);
348 if (valueHolder == null) {
349 valueHolder = getGenericArgumentValue(requiredType, requiredName, usedValueHolders);
350 }
351 return valueHolder;
352 }
353
354 /**
355 * Return the number of argument values held in this instance,
356 * counting both indexed and generic argument values.
357 */
358 public int getArgumentCount() {
359 return (this.indexedArgumentValues.size() + this.genericArgumentValues.size());
360 }
361
362 /**
363 * Return if this holder does not contain any argument values,
364 * neither indexed ones nor generic ones.
365 */
366 public boolean isEmpty() {
367 return (this.indexedArgumentValues.isEmpty() && this.genericArgumentValues.isEmpty());
368 }
369
370 /**
371 * Clear this holder, removing all argument values.
372 */
373 public void clear() {
374 this.indexedArgumentValues.clear();
375 this.genericArgumentValues.clear();
376 }
377
378
379 @Override
380 public boolean equals(Object other) {
381 if (this == other) {
382 return true;
383 }
384 if (!(other instanceof ConstructorArgumentValues)) {
385 return false;
386 }
387 ConstructorArgumentValues that = (ConstructorArgumentValues) other;
388 if (this.genericArgumentValues.size() != that.genericArgumentValues.size() ||
389 this.indexedArgumentValues.size() != that.indexedArgumentValues.size()) {
390 return false;
391 }
392 Iterator<ValueHolder> it1 = this.genericArgumentValues.iterator();
393 Iterator<ValueHolder> it2 = that.genericArgumentValues.iterator();
394 while (it1.hasNext() && it2.hasNext()) {
395 ValueHolder vh1 = it1.next();
396 ValueHolder vh2 = it2.next();
397 if (!vh1.contentEquals(vh2)) {
398 return false;
399 }
400 }
401 for (Map.Entry<Integer, ValueHolder> entry : this.indexedArgumentValues.entrySet()) {
402 ValueHolder vh1 = entry.getValue();
403 ValueHolder vh2 = that.indexedArgumentValues.get(entry.getKey());
404 if (vh2 == null || !vh1.contentEquals(vh2)) {
405 return false;
406 }
407 }
408 return true;
409 }
410
411 @Override
412 public int hashCode() {
413 int hashCode = 7;
414 for (ValueHolder valueHolder : this.genericArgumentValues) {
415 hashCode = 31 * hashCode + valueHolder.contentHashCode();
416 }
417 hashCode = 29 * hashCode;
418 for (Map.Entry<Integer, ValueHolder> entry : this.indexedArgumentValues.entrySet()) {
419 hashCode = 31 * hashCode + (entry.getValue().contentHashCode() ^ entry.getKey().hashCode());
420 }
421 return hashCode;
422 }
423
424
425 /**
426 * Holder for a constructor argument value, with an optional type
427 * attribute indicating the target type of the actual constructor argument.
428 */
429 public static class ValueHolder implements BeanMetadataElement {
430
431 private Object value;
432
433 private String type;
434
435 private String name;
436
437 private Object source;
438
439 private boolean converted = false;
440
441 private Object convertedValue;
442
443 /**
444 * Create a new ValueHolder for the given value.
445 * @param value the argument value
446 */
447 public ValueHolder(Object value) {
448 this.value = value;
449 }
450
451 /**
452 * Create a new ValueHolder for the given value and type.
453 * @param value the argument value
454 * @param type the type of the constructor argument
455 */
456 public ValueHolder(Object value, String type) {
457 this.value = value;
458 this.type = type;
459 }
460
461 /**
462 * Create a new ValueHolder for the given value, type and name.
463 * @param value the argument value
464 * @param type the type of the constructor argument
465 * @param name the name of the constructor argument
466 */
467 public ValueHolder(Object value, String type, String name) {
468 this.value = value;
469 this.type = type;
470 this.name = name;
471 }
472
473 /**
474 * Set the value for the constructor argument.
475 * @see PropertyPlaceholderConfigurer
476 */
477 public void setValue(Object value) {
478 this.value = value;
479 }
480
481 /**
482 * Return the value for the constructor argument.
483 */
484 public Object getValue() {
485 return this.value;
486 }
487
488 /**
489 * Set the type of the constructor argument.
490 */
491 public void setType(String type) {
492 this.type = type;
493 }
494
495 /**
496 * Return the type of the constructor argument.
497 */
498 public String getType() {
499 return this.type;
500 }
501
502 /**
503 * Set the name of the constructor argument.
504 */
505 public void setName(String name) {
506 this.name = name;
507 }
508
509 /**
510 * Return the name of the constructor argument.
511 */
512 public String getName() {
513 return this.name;
514 }
515
516 /**
517 * Set the configuration source {@code Object} for this metadata element.
518 * <p>The exact type of the object will depend on the configuration mechanism used.
519 */
520 public void setSource(Object source) {
521 this.source = source;
522 }
523
524 @Override
525 public Object getSource() {
526 return this.source;
527 }
528
529 /**
530 * Return whether this holder contains a converted value already ({@code true}),
531 * or whether the value still needs to be converted ({@code false}).
532 */
533 public synchronized boolean isConverted() {
534 return this.converted;
535 }
536
537 /**
538 * Set the converted value of the constructor argument,
539 * after processed type conversion.
540 */
541 public synchronized void setConvertedValue(Object value) {
542 this.converted = true;
543 this.convertedValue = value;
544 }
545
546 /**
547 * Return the converted value of the constructor argument,
548 * after processed type conversion.
549 */
550 public synchronized Object getConvertedValue() {
551 return this.convertedValue;
552 }
553
554 /**
555 * Determine whether the content of this ValueHolder is equal
556 * to the content of the given other ValueHolder.
557 * <p>Note that ValueHolder does not implement {@code equals}
558 * directly, to allow for multiple ValueHolder instances with the
559 * same content to reside in the same Set.
560 */
561 private boolean contentEquals(ValueHolder other) {
562 return (this == other ||
563 (ObjectUtils.nullSafeEquals(this.value, other.value) && ObjectUtils.nullSafeEquals(this.type, other.type)));
564 }
565
566 /**
567 * Determine whether the hash code of the content of this ValueHolder.
568 * <p>Note that ValueHolder does not implement {@code hashCode}
569 * directly, to allow for multiple ValueHolder instances with the
570 * same content to reside in the same Set.
571 */
572 private int contentHashCode() {
573 return ObjectUtils.nullSafeHashCode(this.value) * 29 + ObjectUtils.nullSafeHashCode(this.type);
574 }
575
576 /**
577 * Create a copy of this ValueHolder: that is, an independent
578 * ValueHolder instance with the same contents.
579 */
580 public ValueHolder copy() {
581 ValueHolder copy = new ValueHolder(this.value, this.type, this.name);
582 copy.setSource(this.source);
583 return copy;
584 }
585 }
586
587}