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

Save This Page
Home » spring-framework-2.5.6-with-dependencies » org.springframework » beans » factory » support » [javadoc | source]