001: /*
002: * Copyright 2002-2007 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: * http://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:
017: package org.springframework.beans.factory.support;
018:
019: import java.lang.reflect.Constructor;
020: import java.lang.reflect.Method;
021: import java.lang.reflect.Modifier;
022: import java.util.HashSet;
023: import java.util.Iterator;
024: import java.util.Map;
025: import java.util.Set;
026:
027: import org.springframework.beans.BeanMetadataElement;
028: import org.springframework.beans.BeanWrapper;
029: import org.springframework.beans.BeanWrapperImpl;
030: import org.springframework.beans.BeansException;
031: import org.springframework.beans.TypeMismatchException;
032: import org.springframework.beans.factory.BeanCreationException;
033: import org.springframework.beans.factory.BeanDefinitionStoreException;
034: import org.springframework.beans.factory.UnsatisfiedDependencyException;
035: import org.springframework.beans.factory.config.ConstructorArgumentValues;
036: import org.springframework.beans.factory.config.TypedStringValue;
037: import org.springframework.core.MethodParameter;
038: import org.springframework.util.ObjectUtils;
039: import org.springframework.util.ReflectionUtils;
040:
041: /**
042: * Helper class for resolving constructors and factory methods.
043: * Performs constructor resolution through argument matching.
044: *
045: * <p>Operates on an {@link AbstractBeanFactory} and an {@link InstantiationStrategy}.
046: * Used by {@link AbstractAutowireCapableBeanFactory}.
047: *
048: * @author Juergen Hoeller
049: * @author Rob Harrop
050: * @since 2.0
051: * @see #autowireConstructor
052: * @see #instantiateUsingFactoryMethod
053: * @see AbstractAutowireCapableBeanFactory
054: */
055: abstract class ConstructorResolver {
056:
057: private final AbstractBeanFactory beanFactory;
058:
059: private final InstantiationStrategy instantiationStrategy;
060:
061: /**
062: * Create a new ConstructorResolver for the given factory and instantiation strategy.
063: * @param beanFactory the BeanFactory to work with
064: * @param instantiationStrategy the instantiate strategy for creating bean instances
065: */
066: public ConstructorResolver(AbstractBeanFactory beanFactory,
067: InstantiationStrategy instantiationStrategy) {
068: this .beanFactory = beanFactory;
069: this .instantiationStrategy = instantiationStrategy;
070: }
071:
072: /**
073: * "autowire constructor" (with constructor arguments by type) behavior.
074: * Also applied if explicit constructor argument values are specified,
075: * matching all remaining arguments with beans from the bean factory.
076: * <p>This corresponds to constructor injection: In this mode, a Spring
077: * bean factory is able to host components that expect constructor-based
078: * dependency resolution.
079: * @param beanName the name of the bean
080: * @param mbd the merged bean definition for the bean
081: * @param chosenCtor a pre-chosen Constructor (or <code>null</code> if none)
082: * @return a BeanWrapper for the new instance
083: */
084: protected BeanWrapper autowireConstructor(String beanName,
085: RootBeanDefinition mbd, Constructor chosenCtor) {
086: BeanWrapper bw = new BeanWrapperImpl();
087: this .beanFactory.initBeanWrapper(bw);
088:
089: Constructor constructorToUse = (Constructor) mbd.resolvedConstructorOrFactoryMethod;
090: Object[] argsToUse = null;
091:
092: if (constructorToUse != null) {
093: // Found a cached constructor...
094: argsToUse = mbd.resolvedConstructorArguments;
095: if (argsToUse == null) {
096: Class[] paramTypes = constructorToUse
097: .getParameterTypes();
098: Object[] argsToResolve = mbd.preparedConstructorArguments;
099: BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(
100: this .beanFactory, beanName, mbd, bw);
101: argsToUse = new Object[argsToResolve.length];
102: for (int i = 0; i < argsToResolve.length; i++) {
103: Object argValue = argsToResolve[i];
104: if (argValue instanceof BeanMetadataElement) {
105: String argName = "constructor argument with index "
106: + i;
107: argValue = valueResolver
108: .resolveValueIfNecessary(argName,
109: argValue);
110: }
111: argsToUse[i] = bw.convertIfNecessary(argValue,
112: paramTypes[i], new MethodParameter(
113: constructorToUse, i));
114: }
115: }
116: }
117:
118: else {
119: // Need to resolve the constructor.
120: boolean autowiring = (chosenCtor != null || mbd
121: .getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
122:
123: ConstructorArgumentValues cargs = mbd
124: .getConstructorArgumentValues();
125: ConstructorArgumentValues resolvedValues = new ConstructorArgumentValues();
126: int minNrOfArgs = resolveConstructorArguments(beanName,
127: mbd, bw, cargs, resolvedValues);
128:
129: // Take specified constructor, if any.
130: if (chosenCtor != null) {
131: Class[] paramTypes = chosenCtor.getParameterTypes();
132: argsToUse = createArgumentArray(beanName, mbd,
133: resolvedValues, bw, paramTypes, chosenCtor,
134: autowiring).arguments;
135: constructorToUse = chosenCtor;
136: }
137:
138: else {
139: Constructor[] candidates = mbd.getBeanClass()
140: .getDeclaredConstructors();
141: AutowireUtils.sortConstructors(candidates);
142: int minTypeDiffWeight = Integer.MAX_VALUE;
143:
144: for (int i = 0; i < candidates.length; i++) {
145: Constructor candidate = candidates[i];
146: Class[] paramTypes = candidate.getParameterTypes();
147:
148: if (constructorToUse != null
149: && argsToUse.length > paramTypes.length) {
150: // Already found greedy constructor that can be satisfied ->
151: // do not look any further, there are only less greedy constructors left.
152: break;
153: }
154: if (paramTypes.length < minNrOfArgs) {
155: throw new BeanCreationException(
156: mbd.getResourceDescription(),
157: beanName,
158: minNrOfArgs
159: + " constructor arguments specified but no matching constructor found in bean '"
160: + beanName
161: + "' "
162: + "(hint: specify index and/or type arguments for simple parameters to avoid type ambiguities)");
163: }
164:
165: // Try to resolve arguments for current constructor.
166: try {
167: ArgumentsHolder args = createArgumentArray(
168: beanName, mbd, resolvedValues, bw,
169: paramTypes, candidate, autowiring);
170: int typeDiffWeight = args
171: .getTypeDifferenceWeight(paramTypes);
172: // Choose this constructor if it represents the closest match.
173: if (typeDiffWeight < minTypeDiffWeight) {
174: constructorToUse = candidate;
175: argsToUse = args.arguments;
176: minTypeDiffWeight = typeDiffWeight;
177: }
178: } catch (UnsatisfiedDependencyException ex) {
179: if (this .beanFactory.logger.isTraceEnabled()) {
180: this .beanFactory.logger
181: .trace("Ignoring constructor ["
182: + candidate + "] of bean '"
183: + beanName + "': " + ex);
184: }
185: if (i == candidates.length - 1
186: && constructorToUse == null) {
187: throw ex;
188: } else {
189: // Swallow and try next constructor.
190: }
191: }
192: }
193:
194: if (constructorToUse == null) {
195: throw new BeanCreationException(mbd
196: .getResourceDescription(), beanName,
197: "Could not resolve matching constructor");
198: }
199: }
200:
201: mbd.resolvedConstructorOrFactoryMethod = constructorToUse;
202: }
203:
204: Object beanInstance = this .instantiationStrategy.instantiate(
205: mbd, beanName, this .beanFactory, constructorToUse,
206: argsToUse);
207: bw.setWrappedInstance(beanInstance);
208: return bw;
209: }
210:
211: /**
212: * Instantiate the bean using a named factory method. The method may be static, if the
213: * bean definition parameter specifies a class, rather than a "factory-bean", or
214: * an instance variable on a factory object itself configured using Dependency Injection.
215: * <p>Implementation requires iterating over the static or instance methods with the
216: * name specified in the RootBeanDefinition (the method may be overloaded) and trying
217: * to match with the parameters. We don't have the types attached to constructor args,
218: * so trial and error is the only way to go here. The explicitArgs array may contain
219: * argument values passed in programmatically via the corresponding getBean method.
220: * @param beanName the name of the bean
221: * @param mbd the merged bean definition for the bean
222: * @param explicitArgs argument values passed in programmatically via the getBean
223: * method, or <code>null</code> if none (-> use constructor argument values from bean definition)
224: * @return a BeanWrapper for the new instance
225: */
226: public BeanWrapper instantiateUsingFactoryMethod(String beanName,
227: RootBeanDefinition mbd, Object[] explicitArgs) {
228: BeanWrapper bw = new BeanWrapperImpl();
229: this .beanFactory.initBeanWrapper(bw);
230:
231: Class factoryClass = null;
232: Object factoryBean = null;
233: boolean isStatic = true;
234:
235: if (mbd.getFactoryBeanName() != null) {
236: factoryBean = this .beanFactory.getBean(mbd
237: .getFactoryBeanName());
238: factoryClass = factoryBean.getClass();
239: isStatic = false;
240: } else {
241: // It's a static factory method on the bean class.
242: factoryClass = mbd.getBeanClass();
243: }
244:
245: Method factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
246: Object[] argsToUse = null;
247:
248: if (factoryMethodToUse != null) {
249: // Found a cached factory method...
250: if (explicitArgs != null) {
251: argsToUse = explicitArgs;
252: } else {
253: argsToUse = mbd.resolvedConstructorArguments;
254: if (argsToUse == null) {
255: Class[] paramTypes = factoryMethodToUse
256: .getParameterTypes();
257: Object[] argsToResolve = mbd.preparedConstructorArguments;
258: BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(
259: this .beanFactory, beanName, mbd, bw);
260: argsToUse = new Object[argsToResolve.length];
261: for (int i = 0; i < argsToResolve.length; i++) {
262: Object argValue = argsToResolve[i];
263: if (argValue instanceof BeanMetadataElement) {
264: String argName = "factory method argument with index "
265: + i;
266: argValue = valueResolver
267: .resolveValueIfNecessary(argName,
268: argValue);
269: }
270: argsToUse[i] = bw.convertIfNecessary(argValue,
271: paramTypes[i], new MethodParameter(
272: factoryMethodToUse, i));
273: }
274: }
275: }
276: }
277:
278: else {
279: // Need to determine the factory method...
280: // Try all methods with this name to see if they match the given arguments.
281: Method[] candidates = ReflectionUtils
282: .getAllDeclaredMethods(factoryClass);
283: boolean autowiring = (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
284: int minTypeDiffWeight = Integer.MAX_VALUE;
285: ConstructorArgumentValues resolvedValues = null;
286:
287: int minNrOfArgs = 0;
288: if (explicitArgs != null) {
289: minNrOfArgs = explicitArgs.length;
290: } else {
291: // We don't have arguments passed in programmatically, so we need to resolve the
292: // arguments specified in the constructor arguments held in the bean definition.
293: ConstructorArgumentValues cargs = mbd
294: .getConstructorArgumentValues();
295: resolvedValues = new ConstructorArgumentValues();
296: minNrOfArgs = resolveConstructorArguments(beanName,
297: mbd, bw, cargs, resolvedValues);
298: }
299:
300: for (int i = 0; i < candidates.length; i++) {
301: Method candidate = candidates[i];
302: Class[] paramTypes = candidate.getParameterTypes();
303:
304: if (Modifier.isStatic(candidate.getModifiers()) == isStatic
305: && candidate.getName().equals(
306: mbd.getFactoryMethodName())
307: && paramTypes.length >= minNrOfArgs) {
308:
309: ArgumentsHolder args = null;
310:
311: if (resolvedValues != null) {
312: // Resolved contructor arguments: type conversion and/or autowiring necessary.
313: try {
314: args = createArgumentArray(beanName, mbd,
315: resolvedValues, bw, paramTypes,
316: candidate, autowiring);
317: } catch (UnsatisfiedDependencyException ex) {
318: if (this .beanFactory.logger
319: .isTraceEnabled()) {
320: this .beanFactory.logger
321: .trace("Ignoring factory method ["
322: + candidate
323: + "] of bean '"
324: + beanName + "': " + ex);
325: }
326: if (i == candidates.length - 1
327: && factoryMethodToUse == null) {
328: throw ex;
329: } else {
330: // Swallow and try next overloaded factory method.
331: continue;
332: }
333: }
334: }
335:
336: else {
337: // Explicit arguments given -> arguments length must match exactly.
338: if (paramTypes.length != explicitArgs.length) {
339: continue;
340: }
341: args = new ArgumentsHolder(explicitArgs);
342: }
343:
344: int typeDiffWeight = args
345: .getTypeDifferenceWeight(paramTypes);
346: // Choose this constructor if it represents the closest match.
347: if (typeDiffWeight < minTypeDiffWeight) {
348: factoryMethodToUse = candidate;
349: argsToUse = args.arguments;
350: minTypeDiffWeight = typeDiffWeight;
351: }
352: }
353: }
354:
355: if (factoryMethodToUse == null) {
356: throw new BeanDefinitionStoreException(
357: "No matching factory method found: "
358: + (mbd.getFactoryBeanName() != null ? "factory bean '"
359: + mbd.getFactoryBeanName()
360: + "'; "
361: : "") + "factory method '"
362: + mbd.getFactoryMethodName() + "'");
363: }
364: mbd.resolvedConstructorOrFactoryMethod = factoryMethodToUse;
365: }
366:
367: Object beanInstance = this .instantiationStrategy.instantiate(
368: mbd, beanName, this .beanFactory, factoryBean,
369: factoryMethodToUse, argsToUse);
370: if (beanInstance == null) {
371: return null;
372: }
373:
374: bw.setWrappedInstance(beanInstance);
375: return bw;
376: }
377:
378: /**
379: * Resolve the constructor arguments for this bean into the resolvedValues object.
380: * This may involve looking up other beans.
381: * This method is also used for handling invocations of static factory methods.
382: */
383: private int resolveConstructorArguments(String beanName,
384: RootBeanDefinition mbd, BeanWrapper bw,
385: ConstructorArgumentValues cargs,
386: ConstructorArgumentValues resolvedValues) {
387:
388: BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(
389: this .beanFactory, beanName, mbd, bw);
390:
391: int minNrOfArgs = cargs.getArgumentCount();
392:
393: for (Iterator it = cargs.getIndexedArgumentValues().entrySet()
394: .iterator(); it.hasNext();) {
395: Map.Entry entry = (Map.Entry) it.next();
396: int index = ((Integer) entry.getKey()).intValue();
397: if (index < 0) {
398: throw new BeanCreationException(mbd
399: .getResourceDescription(), beanName,
400: "Invalid constructor argument index: " + index);
401: }
402: if (index > minNrOfArgs) {
403: minNrOfArgs = index + 1;
404: }
405: ConstructorArgumentValues.ValueHolder valueHolder = (ConstructorArgumentValues.ValueHolder) entry
406: .getValue();
407: if (valueHolder.isConverted()) {
408: resolvedValues.addIndexedArgumentValue(index,
409: valueHolder);
410: } else {
411: String argName = "constructor argument with index "
412: + index;
413: Object resolvedValue = valueResolver
414: .resolveValueIfNecessary(argName, valueHolder
415: .getValue());
416: ConstructorArgumentValues.ValueHolder resolvedValueHolder = new ConstructorArgumentValues.ValueHolder(
417: resolvedValue, valueHolder.getType());
418: resolvedValueHolder.setSource(valueHolder);
419: resolvedValues.addIndexedArgumentValue(index,
420: resolvedValueHolder);
421: }
422: }
423:
424: for (Iterator it = cargs.getGenericArgumentValues().iterator(); it
425: .hasNext();) {
426: ConstructorArgumentValues.ValueHolder valueHolder = (ConstructorArgumentValues.ValueHolder) it
427: .next();
428: if (valueHolder.isConverted()) {
429: resolvedValues.addGenericArgumentValue(valueHolder);
430: } else {
431: String argName = "constructor argument";
432: Object resolvedValue = valueResolver
433: .resolveValueIfNecessary(argName, valueHolder
434: .getValue());
435: ConstructorArgumentValues.ValueHolder resolvedValueHolder = new ConstructorArgumentValues.ValueHolder(
436: resolvedValue, valueHolder.getType());
437: resolvedValueHolder.setSource(valueHolder);
438: resolvedValues
439: .addGenericArgumentValue(resolvedValueHolder);
440: }
441: }
442:
443: return minNrOfArgs;
444: }
445:
446: /**
447: * Create an array of arguments to invoke a constructor or factory method,
448: * given the resolved constructor argument values.
449: */
450: private ArgumentsHolder createArgumentArray(String beanName,
451: RootBeanDefinition mbd,
452: ConstructorArgumentValues resolvedValues, BeanWrapper bw,
453: Class[] paramTypes, Object methodOrCtor, boolean autowiring)
454: throws UnsatisfiedDependencyException {
455:
456: String methodType = (methodOrCtor instanceof Constructor ? "constructor"
457: : "factory method");
458:
459: ArgumentsHolder args = new ArgumentsHolder(paramTypes.length);
460: Set usedValueHolders = new HashSet(paramTypes.length);
461: boolean resolveNecessary = false;
462:
463: for (int index = 0; index < paramTypes.length; index++) {
464: // Try to find matching constructor argument value, either indexed or generic.
465: ConstructorArgumentValues.ValueHolder valueHolder = resolvedValues
466: .getArgumentValue(index, paramTypes[index],
467: usedValueHolders);
468: // If we couldn't find a direct match and are not supposed to autowire,
469: // let's try the next generic, untyped argument value as fallback:
470: // it could match after type conversion (for example, String -> int).
471: if (valueHolder == null && !autowiring) {
472: valueHolder = resolvedValues.getGenericArgumentValue(
473: null, usedValueHolders);
474: }
475: if (valueHolder != null) {
476: // We found a potential match - let's give it a try.
477: // Do not consider the same value definition multiple times!
478: usedValueHolders.add(valueHolder);
479: args.rawArguments[index] = valueHolder.getValue();
480: if (valueHolder.isConverted()) {
481: Object convertedValue = valueHolder
482: .getConvertedValue();
483: args.arguments[index] = convertedValue;
484: args.preparedArguments[index] = convertedValue;
485: } else {
486: try {
487: Object originalValue = valueHolder.getValue();
488: Object convertedValue = bw.convertIfNecessary(
489: originalValue, paramTypes[index],
490: MethodParameter.forMethodOrConstructor(
491: methodOrCtor, index));
492: args.arguments[index] = convertedValue;
493: ConstructorArgumentValues.ValueHolder sourceHolder = (ConstructorArgumentValues.ValueHolder) valueHolder
494: .getSource();
495: Object sourceValue = sourceHolder.getValue();
496: if (originalValue == sourceValue
497: || sourceValue instanceof TypedStringValue) {
498: // Either a converted value or still the original one: store converted value.
499: sourceHolder
500: .setConvertedValue(convertedValue);
501: args.preparedArguments[index] = convertedValue;
502: } else {
503: resolveNecessary = true;
504: args.preparedArguments[index] = sourceValue;
505: }
506: } catch (TypeMismatchException ex) {
507: throw new UnsatisfiedDependencyException(
508: mbd.getResourceDescription(),
509: beanName,
510: index,
511: paramTypes[index],
512: "Could not convert "
513: + methodType
514: + " argument value of type ["
515: + ObjectUtils
516: .nullSafeClassName(valueHolder
517: .getValue())
518: + "] to required type ["
519: + paramTypes[index].getName()
520: + "]: " + ex.getMessage());
521: }
522: }
523: } else {
524: // No explicit match found: we're either supposed to autowire or
525: // have to fail creating an argument array for the given constructor.
526: if (!autowiring) {
527: throw new UnsatisfiedDependencyException(
528: mbd.getResourceDescription(),
529: beanName,
530: index,
531: paramTypes[index],
532: "Ambiguous "
533: + methodType
534: + " argument types - "
535: + "did you specify the correct bean references as "
536: + methodType + " arguments?");
537: }
538: Map matchingBeans = findAutowireCandidates(beanName,
539: paramTypes[index]);
540: if (matchingBeans.size() != 1) {
541: throw new UnsatisfiedDependencyException(
542: mbd.getResourceDescription(),
543: beanName,
544: index,
545: paramTypes[index],
546: "There are "
547: + matchingBeans.size()
548: + " beans of type ["
549: + paramTypes[index].getName()
550: + "] available for autowiring: "
551: + matchingBeans.keySet()
552: + ". There should have been exactly 1 to be able to autowire "
553: + methodType + " of bean '"
554: + beanName + "'.");
555: }
556: Map.Entry entry = (Map.Entry) matchingBeans.entrySet()
557: .iterator().next();
558: String autowiredBeanName = (String) entry.getKey();
559: Object autowiredBean = entry.getValue();
560: args.rawArguments[index] = autowiredBean;
561: args.arguments[index] = autowiredBean;
562: if (mbd.isSingleton()) {
563: this .beanFactory.registerDependentBean(
564: autowiredBeanName, beanName);
565: }
566: if (this .beanFactory.logger.isDebugEnabled()) {
567: this .beanFactory.logger
568: .debug("Autowiring by type from bean name '"
569: + beanName
570: + "' via "
571: + methodType
572: + " to bean named '"
573: + autowiredBeanName + "'");
574: }
575: }
576: }
577:
578: if (resolveNecessary) {
579: mbd.preparedConstructorArguments = args.preparedArguments;
580: } else {
581: mbd.resolvedConstructorArguments = args.arguments;
582: }
583: return args;
584: }
585:
586: /**
587: * Find bean instances that match the required type.
588: * Called during autowiring for the specified bean.
589: * <p>If a subclass cannot obtain information about bean names by type,
590: * a corresponding exception should be thrown.
591: * @param beanName the name of the bean that is about to be wired
592: * @param requiredType the type of the autowired constructor argument
593: * @return a Map of candidate names and candidate instances that match
594: * the required type (never <code>null</code>)
595: * @throws BeansException in case of errors
596: * @see #autowireConstructor
597: */
598: protected abstract Map findAutowireCandidates(String beanName,
599: Class requiredType) throws BeansException;
600:
601: /**
602: * Private inner class for holding argument combinations.
603: */
604: private static class ArgumentsHolder {
605:
606: public Object rawArguments[];
607:
608: public Object arguments[];
609:
610: public Object preparedArguments[];
611:
612: public ArgumentsHolder(int size) {
613: this .rawArguments = new Object[size];
614: this .arguments = new Object[size];
615: this .preparedArguments = new Object[size];
616: }
617:
618: public ArgumentsHolder(Object[] args) {
619: this .rawArguments = args;
620: this .arguments = args;
621: this .preparedArguments = args;
622: }
623:
624: public int getTypeDifferenceWeight(Class[] paramTypes) {
625: // If valid arguments found, determine type difference weight.
626: // Try type difference weight on both the converted arguments and
627: // the raw arguments. If the raw weight is better, use it.
628: // Decrease raw weight by 1024 to prefer it over equal converted weight.
629: int typeDiffWeight = AutowireUtils.getTypeDifferenceWeight(
630: paramTypes, this .arguments);
631: int rawTypeDiffWeight = AutowireUtils
632: .getTypeDifferenceWeight(paramTypes,
633: this .rawArguments) - 1024;
634: return (rawTypeDiffWeight < typeDiffWeight ? rawTypeDiffWeight
635: : typeDiffWeight);
636: }
637: }
638:
639: }
|