KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > beans > factory > config > ConstructorArgumentValues


1 /*
2  * Copyright 2002-2007 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.beans.factory.config;
18
19 import java.util.Collections JavaDoc;
20 import java.util.HashMap JavaDoc;
21 import java.util.Iterator JavaDoc;
22 import java.util.LinkedList JavaDoc;
23 import java.util.List JavaDoc;
24 import java.util.Map JavaDoc;
25 import java.util.Set JavaDoc;
26
27 import org.springframework.beans.BeanMetadataElement;
28 import org.springframework.beans.Mergeable;
29 import org.springframework.util.Assert;
30 import org.springframework.util.ClassUtils;
31 import org.springframework.util.ObjectUtils;
32
33 /**
34  * Holder for constructor argument values, typically as part of a bean definition.
35  *
36  * <p>Supports values for a specific index in the constructor argument list
37  * as well as for generic argument matches by type.
38  *
39  * @author Juergen Hoeller
40  * @since 09.11.2003
41  * @see BeanDefinition#getConstructorArgumentValues
42  */

43 public class ConstructorArgumentValues {
44
45     private final Map JavaDoc indexedArgumentValues = new HashMap JavaDoc();
46
47     private final List JavaDoc genericArgumentValues = new LinkedList JavaDoc();
48
49
50     /**
51      * Create a new empty ConstructorArgumentValues object.
52      */

53     public ConstructorArgumentValues() {
54     }
55
56     /**
57      * Deep copy constructor.
58      * @param original the ConstructorArgumentValues to copy
59      */

60     public ConstructorArgumentValues(ConstructorArgumentValues original) {
61         addArgumentValues(original);
62     }
63
64     /**
65      * Copy all given argument values into this object, using separate holder
66      * instances to keep the values independent from the original object.
67      * <p>Note: Identical ValueHolder instances will only be registered once,
68      * to allow for merging and re-merging of argument value definitions. Distinct
69      * ValueHolder instances carrying the same content are of course allowed.
70      */

71     public void addArgumentValues(ConstructorArgumentValues other) {
72         if (other != null) {
73             for (Iterator JavaDoc it = other.indexedArgumentValues.entrySet().iterator(); it.hasNext();) {
74                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
75                 ValueHolder valueHolder = (ValueHolder) entry.getValue();
76                 addOrMergeIndexedArgumentValue(entry.getKey(), valueHolder.copy());
77             }
78             for (Iterator JavaDoc it = other.genericArgumentValues.iterator(); it.hasNext();) {
79                 ValueHolder valueHolder = (ValueHolder) it.next();
80                 if (!this.genericArgumentValues.contains(valueHolder)) {
81                     this.genericArgumentValues.add(valueHolder.copy());
82                 }
83             }
84         }
85     }
86
87
88     /**
89      * Add argument value for the given index in the constructor argument list.
90      * @param index the index in the constructor argument list
91      * @param value the argument value
92      */

93     public void addIndexedArgumentValue(int index, Object JavaDoc value) {
94         addIndexedArgumentValue(index, new ValueHolder(value));
95     }
96
97     /**
98      * Add argument value for the given index in the constructor argument list.
99      * @param index the index in the constructor argument list
100      * @param value the argument value
101      * @param type the type of the constructor argument
102      */

103     public void addIndexedArgumentValue(int index, Object JavaDoc value, String JavaDoc type) {
104         addIndexedArgumentValue(index, new ValueHolder(value, type));
105     }
106
107     /**
108      * Add argument value for the given index in the constructor argument list.
109      * @param index the index in the constructor argument list
110      * @param newValue the argument value in the form of a ValueHolder
111      */

112     public void addIndexedArgumentValue(int index, ValueHolder newValue) {
113         Assert.isTrue(index >= 0, "Index must not be negative");
114         Assert.notNull(newValue, "ValueHolder must not be null");
115         addOrMergeIndexedArgumentValue(new Integer JavaDoc(index), newValue);
116     }
117
118     /**
119      * Add argument value for the given index in the constructor argument list,
120      * merging the new value (typically a collection) with the current value
121      * if demanded: see {@link org.springframework.beans.Mergeable}.
122      * @param key the index in the constructor argument list
123      * @param newValue the argument value in the form of a ValueHolder
124      */

125     private void addOrMergeIndexedArgumentValue(Object JavaDoc key, ValueHolder newValue) {
126         ValueHolder currentValue = (ValueHolder) this.indexedArgumentValues.get(key);
127         if (currentValue != null && newValue.getValue() instanceof Mergeable) {
128             Mergeable mergeable = (Mergeable) newValue.getValue();
129             if (mergeable.isMergeEnabled()) {
130                 newValue.setValue(mergeable.merge(currentValue.getValue()));
131             }
132         }
133         this.indexedArgumentValues.put(key, newValue);
134     }
135
136     /**
137      * Get argument value for the given index in the constructor argument list.
138      * @param index the index in the constructor argument list
139      * @param requiredType the type to match (can be <code>null</code> to match
140      * untyped values only)
141      * @return the ValueHolder for the argument, or <code>null</code> if none set
142      */

143     public ValueHolder getIndexedArgumentValue(int index, Class JavaDoc requiredType) {
144         Assert.isTrue(index >= 0, "Index must not be negative");
145         ValueHolder valueHolder = (ValueHolder) this.indexedArgumentValues.get(new Integer JavaDoc(index));
146         if (valueHolder != null) {
147             if (valueHolder.getType() == null ||
148                     (requiredType != null && requiredType.getName().equals(valueHolder.getType()))) {
149                 return valueHolder;
150             }
151         }
152         return null;
153     }
154
155     /**
156      * Return the map of indexed argument values.
157      * @return unmodifiable Map with Integer index as key and ValueHolder as value
158      * @see ValueHolder
159      */

160     public Map JavaDoc getIndexedArgumentValues() {
161         return Collections.unmodifiableMap(this.indexedArgumentValues);
162     }
163
164
165     /**
166      * Add generic argument value to be matched by type.
167      * <p>Note: A single generic argument value will just be used once,
168      * rather than matched multiple times (as of Spring 1.1).
169      * @param value the argument value
170      */

171     public void addGenericArgumentValue(Object JavaDoc value) {
172         this.genericArgumentValues.add(new ValueHolder(value));
173     }
174
175     /**
176      * Add generic argument value to be matched by type.
177      * <p>Note: A single generic argument value will just be used once,
178      * rather than matched multiple times (as of Spring 1.1).
179      * @param value the argument value
180      * @param type the type of the constructor argument
181      */

182     public void addGenericArgumentValue(Object JavaDoc value, String JavaDoc type) {
183         this.genericArgumentValues.add(new ValueHolder(value, type));
184     }
185
186     /**
187      * Add generic argument value to be matched by type.
188      * <p>Note: A single generic argument value will just be used once,
189      * rather than matched multiple times (as of Spring 1.1).
190      * @param newValue the argument value in the form of a ValueHolder
191      * <p>Note: Identical ValueHolder instances will only be registered once,
192      * to allow for merging and re-merging of argument value definitions. Distinct
193      * ValueHolder instances carrying the same content are of course allowed.
194      */

195     public void addGenericArgumentValue(ValueHolder newValue) {
196         Assert.notNull(newValue, "ValueHolder must not be null");
197         if (!this.genericArgumentValues.contains(newValue)) {
198             this.genericArgumentValues.add(newValue);
199         }
200     }
201
202     /**
203      * Look for a generic argument value that matches the given type.
204      * @param requiredType the type to match (can be <code>null</code> to find
205      * an arbitrary next generic argument value)
206      * @return the ValueHolder for the argument, or <code>null</code> if none set
207      */

208     public ValueHolder getGenericArgumentValue(Class JavaDoc requiredType) {
209         return getGenericArgumentValue(requiredType, null);
210     }
211
212     /**
213      * Look for the next generic argument value that matches the given type,
214      * ignoring argument values that have already been used in the current
215      * resolution process.
216      * @param requiredType the type to match (can be <code>null</code> to find
217      * an arbitrary next generic argument value)
218      * @param usedValueHolders a Set of ValueHolder objects that have already been used
219      * in the current resolution process and should therefore not be returned again
220      * @return the ValueHolder for the argument, or <code>null</code> if none found
221      */

222     public ValueHolder getGenericArgumentValue(Class JavaDoc requiredType, Set JavaDoc usedValueHolders) {
223         for (Iterator JavaDoc it = this.genericArgumentValues.iterator(); it.hasNext();) {
224             ValueHolder valueHolder = (ValueHolder) it.next();
225             if (usedValueHolders == null || !usedValueHolders.contains(valueHolder)) {
226                 if (requiredType != null) {
227                     // Check matching type.
228
if (valueHolder.getType() != null) {
229                         if (valueHolder.getType().equals(requiredType.getName())) {
230                             return valueHolder;
231                         }
232                     }
233                     else if (ClassUtils.isAssignableValue(requiredType, valueHolder.getValue())) {
234                         return valueHolder;
235                     }
236                 }
237                 else {
238                     // No required type specified -> consider untyped values only.
239
if (valueHolder.getType() == null) {
240                         return valueHolder;
241                     }
242                 }
243             }
244         }
245         return null;
246     }
247
248     /**
249      * Return the list of generic argument values.
250      * @return unmodifiable List of ValueHolders
251      * @see ValueHolder
252      */

253     public List JavaDoc getGenericArgumentValues() {
254         return Collections.unmodifiableList(this.genericArgumentValues);
255     }
256
257
258     /**
259      * Look for an argument value that either corresponds to the given index
260      * in the constructor argument list or generically matches by type.
261      * @param index the index in the constructor argument list
262      * @param requiredType the type to match
263      * @return the ValueHolder for the argument, or <code>null</code> if none set
264      */

265     public ValueHolder getArgumentValue(int index, Class JavaDoc requiredType) {
266         return getArgumentValue(index, requiredType, null);
267     }
268
269     /**
270      * Look for an argument value that either corresponds to the given index
271      * in the constructor argument list or generically matches by type.
272      * @param index the index in the constructor argument list
273      * @param requiredType the type to match (can be <code>null</code> to find
274      * an untyped argument value)
275      * @param usedValueHolders a Set of ValueHolder objects that have already
276      * been used in the current resolution process and should therefore not
277      * be returned again (allowing to return the next generic argument match
278      * in case of multiple generic argument values of the same type)
279      * @return the ValueHolder for the argument, or <code>null</code> if none set
280      */

281     public ValueHolder getArgumentValue(int index, Class JavaDoc requiredType, Set JavaDoc usedValueHolders) {
282         Assert.isTrue(index >= 0, "Index must not be negative");
283         ValueHolder valueHolder = getIndexedArgumentValue(index, requiredType);
284         if (valueHolder == null) {
285             valueHolder = getGenericArgumentValue(requiredType, usedValueHolders);
286         }
287         return valueHolder;
288     }
289
290     /**
291      * Return the number of argument values held in this instance,
292      * counting both indexed and generic argument values.
293      */

294     public int getArgumentCount() {
295         return (this.indexedArgumentValues.size() + this.genericArgumentValues.size());
296     }
297
298     /**
299      * Return if this holder does not contain any argument values,
300      * neither indexed ones nor generic ones.
301      */

302     public boolean isEmpty() {
303         return (this.indexedArgumentValues.isEmpty() && this.genericArgumentValues.isEmpty());
304     }
305
306     /**
307      * Clear this holder, removing all argument values.
308      */

309     public void clear() {
310         this.indexedArgumentValues.clear();
311         this.genericArgumentValues.clear();
312     }
313
314
315     public boolean equals(Object JavaDoc other) {
316         if (this == other) {
317             return true;
318         }
319         if (!(other instanceof ConstructorArgumentValues)) {
320             return false;
321         }
322         ConstructorArgumentValues that = (ConstructorArgumentValues) other;
323         if (this.genericArgumentValues.size() != that.genericArgumentValues.size() ||
324                 this.indexedArgumentValues.size() != that.indexedArgumentValues.size()) {
325             return false;
326         }
327         Iterator JavaDoc it1 = this.genericArgumentValues.iterator();
328         Iterator JavaDoc it2 = that.genericArgumentValues.iterator();
329         while (it1.hasNext() && it2.hasNext()) {
330             ValueHolder vh1 = (ValueHolder) it1.next();
331             ValueHolder vh2 = (ValueHolder) it2.next();
332             if (!vh1.contentEquals(vh2)) {
333                 return false;
334             }
335         }
336         for (Iterator JavaDoc it = this.indexedArgumentValues.entrySet().iterator(); it.hasNext();) {
337             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
338             ValueHolder vh1 = (ValueHolder) entry.getValue();
339             ValueHolder vh2 = (ValueHolder) that.indexedArgumentValues.get(entry.getKey());
340             if (!vh1.contentEquals(vh2)) {
341                 return false;
342             }
343         }
344         return true;
345     }
346
347     public int hashCode() {
348         int hashCode = 7;
349         for (Iterator JavaDoc it = this.genericArgumentValues.iterator(); it.hasNext();) {
350             ValueHolder valueHolder = (ValueHolder) it.next();
351             hashCode = 31 * hashCode + valueHolder.contentHashCode();
352         }
353         hashCode = 29 * hashCode;
354         for (Iterator JavaDoc it = this.indexedArgumentValues.entrySet().iterator(); it.hasNext();) {
355             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
356             Integer JavaDoc key = (Integer JavaDoc) entry.getKey();
357             ValueHolder value = (ValueHolder) entry.getValue();
358             hashCode = 31 * hashCode + (value.contentHashCode() ^ key.hashCode());
359         }
360         return hashCode;
361     }
362
363
364     /**
365      * Holder for a constructor argument value, with an optional type
366      * attribute indicating the target type of the actual constructor argument.
367      */

368     public static class ValueHolder implements BeanMetadataElement {
369
370         private Object JavaDoc value;
371
372         private String JavaDoc type;
373
374         private Object JavaDoc source;
375
376         /**
377          * Create a new ValueHolder for the given value.
378          * @param value the argument value
379          */

380         public ValueHolder(Object JavaDoc value) {
381             this.value = value;
382         }
383
384         /**
385          * Create a new ValueHolder for the given value and type.
386          * @param value the argument value
387          * @param type the type of the constructor argument
388          */

389         public ValueHolder(Object JavaDoc value, String JavaDoc type) {
390             this.value = value;
391             this.type = type;
392         }
393
394         /**
395          * Set the value for the constructor argument.
396          * Only necessary for manipulating a registered value,
397          * for example in BeanFactoryPostProcessors.
398          * @see PropertyPlaceholderConfigurer
399          */

400         public void setValue(Object JavaDoc value) {
401             this.value = value;
402         }
403
404         /**
405          * Return the value for the constructor argument.
406          */

407         public Object JavaDoc getValue() {
408             return this.value;
409         }
410
411         /**
412          * Set the type of the constructor argument.
413          * Only necessary for manipulating a registered value,
414          * for example in BeanFactoryPostProcessors.
415          * @see PropertyPlaceholderConfigurer
416          */

417         public void setType(String JavaDoc type) {
418             this.type = type;
419         }
420
421         /**
422          * Return the type of the constructor argument.
423          */

424         public String JavaDoc getType() {
425             return this.type;
426         }
427
428         /**
429          * Set the configuration source <code>Object</code> for this metadata element.
430          * <p>The exact type of the object will depend on the configuration mechanism used.
431          */

432         public void setSource(Object JavaDoc source) {
433             this.source = source;
434         }
435
436         public Object JavaDoc getSource() {
437             return this.source;
438         }
439
440         /**
441          * Determine whether the content of this ValueHolder is equal
442          * to the content of the given other ValueHolder.
443          * <p>Note that ValueHolder does not implement <code>equals</code>
444          * directly, to allow for multiple ValueHolder instances with the
445          * same content to reside in the same Set.
446          */

447         private boolean contentEquals(ValueHolder other) {
448             return (this == other ||
449                     (ObjectUtils.nullSafeEquals(this.value, other.value) && ObjectUtils.nullSafeEquals(this.type, other.type)));
450         }
451
452         /**
453          * Determine whether the hash code of the content of this ValueHolder.
454          * <p>Note that ValueHolder does not implement <code>hashCode</code>
455          * directly, to allow for multiple ValueHolder instances with the
456          * same content to reside in the same Set.
457          */

458         private int contentHashCode() {
459             return ObjectUtils.nullSafeHashCode(this.value) * 29 + ObjectUtils.nullSafeHashCode(this.type);
460         }
461
462         /**
463          * Create a copy of this ValueHolder: that is, an independent
464          * ValueHolder instance with the same contents.
465          */

466         public ValueHolder copy() {
467             ValueHolder copy = new ValueHolder(this.value, this.type);
468             copy.setSource(this.source);
469             return copy;
470         }
471     }
472
473 }
474
Popular Tags