KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > beans > factory > support > BeanDefinitionValueResolver


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.support;
18
19 import java.util.ArrayList JavaDoc;
20 import java.util.Iterator JavaDoc;
21 import java.util.List JavaDoc;
22 import java.util.Map JavaDoc;
23 import java.util.Properties JavaDoc;
24 import java.util.Set JavaDoc;
25
26 import org.springframework.beans.BeanWrapper;
27 import org.springframework.beans.BeansException;
28 import org.springframework.beans.TypeConverter;
29 import org.springframework.beans.factory.BeanCreationException;
30 import org.springframework.beans.factory.BeanDefinitionStoreException;
31 import org.springframework.beans.factory.config.BeanDefinition;
32 import org.springframework.beans.factory.config.BeanDefinitionHolder;
33 import org.springframework.beans.factory.config.RuntimeBeanNameReference;
34 import org.springframework.beans.factory.config.RuntimeBeanReference;
35 import org.springframework.beans.factory.config.TypedStringValue;
36 import org.springframework.core.CollectionFactory;
37
38 /**
39  * Helper class for use in bean factory implementations,
40  * resolving values contained in bean definition objects
41  * into the actual values applied to the target bean instance.
42  *
43  * <p>Operates on an {@link AbstractBeanFactory} and a plain
44  * {@link org.springframework.beans.factory.config.BeanDefinition} object.
45  * Used by {@link AbstractAutowireCapableBeanFactory}.
46  *
47  * @author Juergen Hoeller
48  * @since 1.2
49  * @see AbstractAutowireCapableBeanFactory
50  */

51 class BeanDefinitionValueResolver {
52
53     /**
54      * Separator for generated bean names. If a class name or parent name is not
55      * unique, "#1", "#2" etc will be appended, until the name becomes unique.
56      */

57     public static final String JavaDoc GENERATED_BEAN_NAME_SEPARATOR =
58             BeanDefinitionReaderUtils.GENERATED_BEAN_NAME_SEPARATOR;
59
60
61     private final AbstractBeanFactory beanFactory;
62
63     private final String JavaDoc beanName;
64
65     private final BeanDefinition beanDefinition;
66
67     private final TypeConverter typeConverter;
68
69
70     /**
71      * Create a new BeanDefinitionValueResolver for the given BeanFactory
72      * and BeanDefinition.
73      * @param beanFactory the BeanFactory to resolve against
74      * @param beanName the name of the bean that we work on
75      * @param beanDefinition the BeanDefinition of the bean that we work on
76      * @param typeConverter the TypeConverter to use for resolving TypedStringValues
77      */

78     public BeanDefinitionValueResolver(
79             AbstractBeanFactory beanFactory, String JavaDoc beanName, BeanDefinition beanDefinition, TypeConverter typeConverter) {
80
81         this.beanFactory = beanFactory;
82         this.beanName = beanName;
83         this.beanDefinition = beanDefinition;
84         this.typeConverter = typeConverter;
85     }
86
87     /**
88      * Given a PropertyValue, return a value, resolving any references to other
89      * beans in the factory if necessary. The value could be:
90      * <li>A BeanDefinition, which leads to the creation of a corresponding
91      * new bean instance. Singleton flags and names of such "inner beans"
92      * are always ignored: Inner beans are anonymous prototypes.
93      * <li>A RuntimeBeanReference, which must be resolved.
94      * <li>A ManagedList. This is a special collection that may contain
95      * RuntimeBeanReferences or Collections that will need to be resolved.
96      * <li>A ManagedSet. May also contain RuntimeBeanReferences or
97      * Collections that will need to be resolved.
98      * <li>A ManagedMap. In this case the value may be a RuntimeBeanReference
99      * or Collection that will need to be resolved.
100      * <li>An ordinary object or <code>null</code>, in which case it's left alone.
101      * @param argName the name of the argument that the value is defined for
102      * @param value the value object to resolve
103      * @return the resolved object
104      */

105     public Object JavaDoc resolveValueIfNecessary(String JavaDoc argName, Object JavaDoc value) {
106         // We must check each value to see whether it requires a runtime reference
107
// to another bean to be resolved.
108
if (value instanceof BeanDefinitionHolder) {
109             // Resolve BeanDefinitionHolder: contains BeanDefinition with name and aliases.
110
BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;
111             return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
112         }
113         else if (value instanceof BeanDefinition) {
114             // Resolve plain BeanDefinition, without contained name: use dummy name.
115
BeanDefinition bd = (BeanDefinition) value;
116             return resolveInnerBean(argName, "(inner bean)", bd);
117         }
118         else if (value instanceof RuntimeBeanNameReference) {
119             String JavaDoc ref = ((RuntimeBeanNameReference) value).getBeanName();
120             if (!this.beanFactory.containsBean(ref)) {
121                 throw new BeanDefinitionStoreException(
122                         "Invalid bean name '" + ref + "' in bean reference for " + argName);
123             }
124             return ref;
125         }
126         else if (value instanceof RuntimeBeanReference) {
127             RuntimeBeanReference ref = (RuntimeBeanReference) value;
128             return resolveReference(argName, ref);
129         }
130         else if (value instanceof ManagedList) {
131             // May need to resolve contained runtime references.
132
return resolveManagedList(argName, (List JavaDoc) value);
133         }
134         else if (value instanceof ManagedSet) {
135             // May need to resolve contained runtime references.
136
return resolveManagedSet(argName, (Set JavaDoc) value);
137         }
138         else if (value instanceof ManagedMap) {
139             // May need to resolve contained runtime references.
140
return resolveManagedMap(argName, (Map JavaDoc) value);
141         }
142         else if (value instanceof ManagedProperties) {
143             Properties JavaDoc original = (Properties JavaDoc) value;
144             Properties JavaDoc copy = new Properties JavaDoc();
145             for (Iterator JavaDoc it = original.entrySet().iterator(); it.hasNext();) {
146                 Map.Entry JavaDoc propEntry = (Map.Entry JavaDoc) it.next();
147                 Object JavaDoc propKey = propEntry.getKey();
148                 Object JavaDoc propValue = propEntry.getValue();
149                 if (propKey instanceof TypedStringValue) {
150                     propKey = ((TypedStringValue) propKey).getValue();
151                 }
152                 if (propValue instanceof TypedStringValue) {
153                     propValue = ((TypedStringValue) propValue).getValue();
154                 }
155                 copy.put(propKey, propValue);
156             }
157             return copy;
158         }
159         else if (value instanceof TypedStringValue) {
160             // Convert value to target type here.
161
TypedStringValue typedStringValue = (TypedStringValue) value;
162             try {
163                 Class JavaDoc resolvedTargetType = resolveTargetType(typedStringValue);
164                 if (resolvedTargetType != null) {
165                     return this.beanFactory.doTypeConversionIfNecessary(
166                             this.typeConverter, typedStringValue.getValue(), resolvedTargetType, null);
167                 }
168                 else {
169                     // No target type specified - no conversion necessary...
170
return typedStringValue.getValue();
171                 }
172             }
173             catch (Throwable JavaDoc ex) {
174                 // Improve the message by showing the context.
175
throw new BeanCreationException(
176                         this.beanDefinition.getResourceDescription(), this.beanName,
177                         "Error converting typed String value for " + argName, ex);
178             }
179         }
180         else {
181             // No need to resolve value...
182
return value;
183         }
184     }
185
186     /**
187      * Resolve the target type in the given TypedStringValue.
188      * @param value the TypedStringValue to resolve
189      * @return the resolved target type (or <code>null</code> if none specified)
190      * @throws ClassNotFoundException if the specified type cannot be resolved
191      * @see TypedStringValue#resolveTargetType
192      */

193     protected Class JavaDoc resolveTargetType(TypedStringValue value) throws ClassNotFoundException JavaDoc {
194         if (value.hasTargetType()) {
195             return value.getTargetType();
196         }
197         return value.resolveTargetType(this.beanFactory.getBeanClassLoader());
198     }
199
200     /**
201      * Resolve an inner bean definition.
202      * @param argName the name of the argument that the inner bean is defined for
203      * @param innerBeanName the name of the inner bean
204      * @param innerBd the bean definition for the inner bean
205      * @return the resolved inner bean instance
206      */

207     private Object JavaDoc resolveInnerBean(String JavaDoc argName, String JavaDoc innerBeanName, BeanDefinition innerBd) {
208         if (this.beanFactory.logger.isTraceEnabled()) {
209             this.beanFactory.logger.trace(
210                     "Resolving inner bean definition '" + innerBeanName + "' of bean '" + this.beanName + "'");
211         }
212         RootBeanDefinition mbd = null;
213         try {
214             mbd = this.beanFactory.getMergedBeanDefinition(innerBeanName, innerBd, this.beanDefinition);
215             // Check given bean name whether it is unique. If not already unique,
216
// add counter - increasing the counter until the name is unique.
217
String JavaDoc actualInnerBeanName = innerBeanName;
218             if (mbd.isSingleton()) {
219                 actualInnerBeanName = adaptInnerBeanName(innerBeanName);
220             }
221             Object JavaDoc innerBean = this.beanFactory.createBean(actualInnerBeanName, mbd, null);
222             if (mbd.isSingleton()) {
223                 this.beanFactory.registerDependentBean(actualInnerBeanName, this.beanName);
224             }
225             return this.beanFactory.getObjectForBeanInstance(innerBean, actualInnerBeanName, mbd);
226         }
227         catch (BeansException ex) {
228             throw new BeanCreationException(
229                     this.beanDefinition.getResourceDescription(), this.beanName,
230                     "Cannot create inner bean '" + innerBeanName + "' " +
231                     (mbd != null && mbd.getBeanClassName() != null ? "of type [" + mbd.getBeanClassName() + "] " : "") +
232                     "while setting " + argName, ex);
233         }
234     }
235
236     /**
237      * Checks the given bean name whether it is unique. If not already unique,
238      * a counter is added, increasing the counter until the name is unique.
239      * @param innerBeanName the original name for the inner bean
240      * @return the adapted name for the inner bean
241      */

242     private String JavaDoc adaptInnerBeanName(String JavaDoc innerBeanName) {
243         String JavaDoc actualInnerBeanName = innerBeanName;
244         int counter = 0;
245         while (this.beanFactory.isBeanNameInUse(actualInnerBeanName)) {
246             counter++;
247             actualInnerBeanName = innerBeanName + GENERATED_BEAN_NAME_SEPARATOR + counter;
248         }
249         return actualInnerBeanName;
250     }
251
252     /**
253      * Resolve a reference to another bean in the factory.
254      */

255     private Object JavaDoc resolveReference(String JavaDoc argName, RuntimeBeanReference ref) {
256         if (this.beanFactory.logger.isTraceEnabled()) {
257             this.beanFactory.logger.trace("Resolving reference from property " + argName + " in bean '" +
258                     this.beanName + "' to bean '" + ref.getBeanName() + "'");
259         }
260         try {
261             if (ref.isToParent()) {
262                 if (this.beanFactory.getParentBeanFactory() == null) {
263                     throw new BeanCreationException(
264                             this.beanDefinition.getResourceDescription(), this.beanName,
265                             "Can't resolve reference to bean '" + ref.getBeanName() +
266                             "' in parent factory: no parent factory available");
267                 }
268                 return this.beanFactory.getParentBeanFactory().getBean(ref.getBeanName());
269             }
270             else {
271                 Object JavaDoc bean = this.beanFactory.getBean(ref.getBeanName());
272                 if (this.beanDefinition.isSingleton()) {
273                     this.beanFactory.registerDependentBean(ref.getBeanName(), this.beanName);
274                 }
275                 return bean;
276             }
277         }
278         catch (BeansException ex) {
279             throw new BeanCreationException(
280                     this.beanDefinition.getResourceDescription(), this.beanName,
281                     "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
282         }
283     }
284
285     /**
286      * For each element in the ManagedList, resolve reference if necessary.
287      */

288     private List JavaDoc resolveManagedList(String JavaDoc argName, List JavaDoc ml) {
289         List JavaDoc resolved = new ArrayList JavaDoc(ml.size());
290         for (int i = 0; i < ml.size(); i++) {
291             resolved.add(
292                 resolveValueIfNecessary(
293                             argName + " with key " + BeanWrapper.PROPERTY_KEY_PREFIX + i + BeanWrapper.PROPERTY_KEY_SUFFIX,
294                             ml.get(i)));
295         }
296         return resolved;
297     }
298
299     /**
300      * For each element in the ManagedList, resolve reference if necessary.
301      */

302     private Set JavaDoc resolveManagedSet(String JavaDoc argName, Set JavaDoc ms) {
303         Set JavaDoc resolved = CollectionFactory.createLinkedSetIfPossible(ms.size());
304         int i = 0;
305         for (Iterator JavaDoc it = ms.iterator(); it.hasNext();) {
306             resolved.add(
307                 resolveValueIfNecessary(
308                             argName + " with key " + BeanWrapper.PROPERTY_KEY_PREFIX + i + BeanWrapper.PROPERTY_KEY_SUFFIX,
309                             it.next()));
310             i++;
311         }
312         return resolved;
313     }
314
315     /**
316      * For each element in the ManagedMap, resolve reference if necessary.
317      */

318     private Map JavaDoc resolveManagedMap(String JavaDoc argName, Map JavaDoc mm) {
319         Map JavaDoc resolved = CollectionFactory.createLinkedMapIfPossible(mm.size());
320         Iterator JavaDoc it = mm.entrySet().iterator();
321         while (it.hasNext()) {
322             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
323             Object JavaDoc resolvedKey = resolveValueIfNecessary(argName, entry.getKey());
324             Object JavaDoc resolvedValue = resolveValueIfNecessary(
325                     argName + " with key " + BeanWrapper.PROPERTY_KEY_PREFIX + entry.getKey() + BeanWrapper.PROPERTY_KEY_SUFFIX,
326                     entry.getValue());
327             resolved.put(resolvedKey, resolvedValue);
328         }
329         return resolved;
330     }
331
332 }
333
Popular Tags