1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.beans.factory.support;
18
19 import java.lang.reflect.Array;
20 import java.util.ArrayList;
21 import java.util.LinkedHashMap;
22 import java.util.LinkedHashSet;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Properties;
26 import java.util.Set;
27
28 import org.springframework.beans.BeanWrapper;
29 import org.springframework.beans.BeansException;
30 import org.springframework.beans.TypeConverter;
31 import org.springframework.beans.factory.BeanCreationException;
32 import org.springframework.beans.factory.BeanDefinitionStoreException;
33 import org.springframework.beans.factory.BeanFactoryUtils;
34 import org.springframework.beans.factory.FactoryBean;
35 import org.springframework.beans.factory.config.BeanDefinition;
36 import org.springframework.beans.factory.config.BeanDefinitionHolder;
37 import org.springframework.beans.factory.config.RuntimeBeanNameReference;
38 import org.springframework.beans.factory.config.RuntimeBeanReference;
39 import org.springframework.beans.factory.config.TypedStringValue;
40 import org.springframework.util.ClassUtils;
41 import org.springframework.util.ObjectUtils;
42 import org.springframework.util.StringUtils;
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 class BeanDefinitionValueResolver {
58
59 private final AbstractBeanFactory beanFactory;
60
61 private final String beanName;
62
63 private final BeanDefinition beanDefinition;
64
65 private final TypeConverter typeConverter;
66
67
68
69
70
71
72
73
74
75 public BeanDefinitionValueResolver(
76 AbstractBeanFactory beanFactory, String beanName, BeanDefinition beanDefinition, TypeConverter typeConverter) {
77
78 this.beanFactory = beanFactory;
79 this.beanName = beanName;
80 this.beanDefinition = beanDefinition;
81 this.typeConverter = typeConverter;
82 }
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103 public Object resolveValueIfNecessary(Object argName, Object value) {
104
105
106 if (value instanceof RuntimeBeanReference) {
107 RuntimeBeanReference ref = (RuntimeBeanReference) value;
108 return resolveReference(argName, ref);
109 }
110 else if (value instanceof RuntimeBeanNameReference) {
111 String refName = ((RuntimeBeanNameReference) value).getBeanName();
112 refName = String.valueOf(doEvaluate(refName));
113 if (!this.beanFactory.containsBean(refName)) {
114 throw new BeanDefinitionStoreException(
115 "Invalid bean name '" + refName + "' in bean reference for " + argName);
116 }
117 return refName;
118 }
119 else if (value instanceof BeanDefinitionHolder) {
120
121 BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;
122 return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
123 }
124 else if (value instanceof BeanDefinition) {
125
126 BeanDefinition bd = (BeanDefinition) value;
127 String innerBeanName = "(inner bean)" + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR +
128 ObjectUtils.getIdentityHexString(bd);
129 return resolveInnerBean(argName, innerBeanName, bd);
130 }
131 else if (value instanceof ManagedArray) {
132
133 ManagedArray array = (ManagedArray) value;
134 Class<?> elementType = array.resolvedElementType;
135 if (elementType == null) {
136 String elementTypeName = array.getElementTypeName();
137 if (StringUtils.hasText(elementTypeName)) {
138 try {
139 elementType = ClassUtils.forName(elementTypeName, this.beanFactory.getBeanClassLoader());
140 array.resolvedElementType = elementType;
141 }
142 catch (Throwable ex) {
143
144 throw new BeanCreationException(
145 this.beanDefinition.getResourceDescription(), this.beanName,
146 "Error resolving array type for " + argName, ex);
147 }
148 }
149 else {
150 elementType = Object.class;
151 }
152 }
153 return resolveManagedArray(argName, (List<?>) value, elementType);
154 }
155 else if (value instanceof ManagedList) {
156
157 return resolveManagedList(argName, (List<?>) value);
158 }
159 else if (value instanceof ManagedSet) {
160
161 return resolveManagedSet(argName, (Set<?>) value);
162 }
163 else if (value instanceof ManagedMap) {
164
165 return resolveManagedMap(argName, (Map<?, ?>) value);
166 }
167 else if (value instanceof ManagedProperties) {
168 Properties original = (Properties) value;
169 Properties copy = new Properties();
170 for (Map.Entry<Object, Object> propEntry : original.entrySet()) {
171 Object propKey = propEntry.getKey();
172 Object propValue = propEntry.getValue();
173 if (propKey instanceof TypedStringValue) {
174 propKey = evaluate((TypedStringValue) propKey);
175 }
176 if (propValue instanceof TypedStringValue) {
177 propValue = evaluate((TypedStringValue) propValue);
178 }
179 copy.put(propKey, propValue);
180 }
181 return copy;
182 }
183 else if (value instanceof TypedStringValue) {
184
185 TypedStringValue typedStringValue = (TypedStringValue) value;
186 Object valueObject = evaluate(typedStringValue);
187 try {
188 Class<?> resolvedTargetType = resolveTargetType(typedStringValue);
189 if (resolvedTargetType != null) {
190 return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType);
191 }
192 else {
193 return valueObject;
194 }
195 }
196 catch (Throwable ex) {
197
198 throw new BeanCreationException(
199 this.beanDefinition.getResourceDescription(), this.beanName,
200 "Error converting typed String value for " + argName, ex);
201 }
202 }
203 else {
204 return evaluate(value);
205 }
206 }
207
208
209
210
211
212
213 protected Object evaluate(TypedStringValue value) {
214 Object result = doEvaluate(value.getValue());
215 if (!ObjectUtils.nullSafeEquals(result, value.getValue())) {
216 value.setDynamic();
217 }
218 return result;
219 }
220
221
222
223
224
225
226 protected Object evaluate(Object value) {
227 if (value instanceof String) {
228 return doEvaluate((String) value);
229 }
230 else if (value instanceof String[]) {
231 String[] values = (String[]) value;
232 boolean actuallyResolved = false;
233 Object[] resolvedValues = new Object[values.length];
234 for (int i = 0; i < values.length; i++) {
235 String originalValue = values[i];
236 Object resolvedValue = doEvaluate(originalValue);
237 if (resolvedValue != originalValue) {
238 actuallyResolved = true;
239 }
240 resolvedValues[i] = resolvedValue;
241 }
242 return (actuallyResolved ? resolvedValues : values);
243 }
244 else {
245 return value;
246 }
247 }
248
249
250
251
252
253
254 private Object doEvaluate(String value) {
255 return this.beanFactory.evaluateBeanDefinitionString(value, this.beanDefinition);
256 }
257
258
259
260
261
262
263
264
265 protected Class<?> resolveTargetType(TypedStringValue value) throws ClassNotFoundException {
266 if (value.hasTargetType()) {
267 return value.getTargetType();
268 }
269 return value.resolveTargetType(this.beanFactory.getBeanClassLoader());
270 }
271
272
273
274
275
276
277
278
279 private Object resolveInnerBean(Object argName, String innerBeanName, BeanDefinition innerBd) {
280 RootBeanDefinition mbd = null;
281 try {
282 mbd = this.beanFactory.getMergedBeanDefinition(innerBeanName, innerBd, this.beanDefinition);
283
284
285 String actualInnerBeanName = innerBeanName;
286 if (mbd.isSingleton()) {
287 actualInnerBeanName = adaptInnerBeanName(innerBeanName);
288 }
289 this.beanFactory.registerContainedBean(actualInnerBeanName, this.beanName);
290
291 String[] dependsOn = mbd.getDependsOn();
292 if (dependsOn != null) {
293 for (String dependsOnBean : dependsOn) {
294 this.beanFactory.registerDependentBean(dependsOnBean, actualInnerBeanName);
295 this.beanFactory.getBean(dependsOnBean);
296 }
297 }
298
299 Object innerBean = this.beanFactory.createBean(actualInnerBeanName, mbd, null);
300 if (innerBean instanceof FactoryBean) {
301 boolean synthetic = mbd.isSynthetic();
302 return this.beanFactory.getObjectFromFactoryBean(
303 (FactoryBean<?>) innerBean, actualInnerBeanName, !synthetic);
304 }
305 else {
306 return innerBean;
307 }
308 }
309 catch (BeansException ex) {
310 throw new BeanCreationException(
311 this.beanDefinition.getResourceDescription(), this.beanName,
312 "Cannot create inner bean '" + innerBeanName + "' " +
313 (mbd != null && mbd.getBeanClassName() != null ? "of type [" + mbd.getBeanClassName() + "] " : "") +
314 "while setting " + argName, ex);
315 }
316 }
317
318
319
320
321
322
323
324 private String adaptInnerBeanName(String innerBeanName) {
325 String actualInnerBeanName = innerBeanName;
326 int counter = 0;
327 while (this.beanFactory.isBeanNameInUse(actualInnerBeanName)) {
328 counter++;
329 actualInnerBeanName = innerBeanName + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR + counter;
330 }
331 return actualInnerBeanName;
332 }
333
334
335
336
337 private Object resolveReference(Object argName, RuntimeBeanReference ref) {
338 try {
339 String refName = ref.getBeanName();
340 refName = String.valueOf(doEvaluate(refName));
341 if (ref.isToParent()) {
342 if (this.beanFactory.getParentBeanFactory() == null) {
343 throw new BeanCreationException(
344 this.beanDefinition.getResourceDescription(), this.beanName,
345 "Can't resolve reference to bean '" + refName +
346 "' in parent factory: no parent factory available");
347 }
348 return this.beanFactory.getParentBeanFactory().getBean(refName);
349 }
350 else {
351 Object bean = this.beanFactory.getBean(refName);
352 this.beanFactory.registerDependentBean(refName, this.beanName);
353 return bean;
354 }
355 }
356 catch (BeansException ex) {
357 throw new BeanCreationException(
358 this.beanDefinition.getResourceDescription(), this.beanName,
359 "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
360 }
361 }
362
363
364
365
366 private Object resolveManagedArray(Object argName, List<?> ml, Class<?> elementType) {
367 Object resolved = Array.newInstance(elementType, ml.size());
368 for (int i = 0; i < ml.size(); i++) {
369 Array.set(resolved, i,
370 resolveValueIfNecessary(new KeyedArgName(argName, i), ml.get(i)));
371 }
372 return resolved;
373 }
374
375
376
377
378 private List<?> resolveManagedList(Object argName, List<?> ml) {
379 List<Object> resolved = new ArrayList<Object>(ml.size());
380 for (int i = 0; i < ml.size(); i++) {
381 resolved.add(
382 resolveValueIfNecessary(new KeyedArgName(argName, i), ml.get(i)));
383 }
384 return resolved;
385 }
386
387
388
389
390 private Set<?> resolveManagedSet(Object argName, Set<?> ms) {
391 Set<Object> resolved = new LinkedHashSet<Object>(ms.size());
392 int i = 0;
393 for (Object m : ms) {
394 resolved.add(resolveValueIfNecessary(new KeyedArgName(argName, i), m));
395 i++;
396 }
397 return resolved;
398 }
399
400
401
402
403 private Map<?, ?> resolveManagedMap(Object argName, Map<?, ?> mm) {
404 Map<Object, Object> resolved = new LinkedHashMap<Object, Object>(mm.size());
405 for (Map.Entry<?, ?> entry : mm.entrySet()) {
406 Object resolvedKey = resolveValueIfNecessary(argName, entry.getKey());
407 Object resolvedValue = resolveValueIfNecessary(
408 new KeyedArgName(argName, entry.getKey()), entry.getValue());
409 resolved.put(resolvedKey, resolvedValue);
410 }
411 return resolved;
412 }
413
414
415
416
417
418 private static class KeyedArgName {
419
420 private final Object argName;
421
422 private final Object key;
423
424 public KeyedArgName(Object argName, Object key) {
425 this.argName = argName;
426 this.key = key;
427 }
428
429 @Override
430 public String toString() {
431 return this.argName + " with key " + BeanWrapper.PROPERTY_KEY_PREFIX +
432 this.key + BeanWrapper.PROPERTY_KEY_SUFFIX;
433 }
434 }
435
436 }