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