/** * Resolve the factory method in the specified bean definition, if possible. {@link * RootBeanDefinition#getResolvedFactoryMethod()} can be checked for the result. * * @param mbd the bean definition to check */ public void resolveFactoryMethodIfPossible(RootBeanDefinition mbd) { Class<?> factoryClass; boolean isStatic; if (mbd.getFactoryBeanName() != null) { factoryClass = this.beanFactory.getType(mbd.getFactoryBeanName()); isStatic = false; } else { factoryClass = mbd.getBeanClass(); isStatic = true; } factoryClass = ClassUtils.getUserClass(factoryClass); Method[] candidates = getCandidateMethods(factoryClass, mbd); Method uniqueCandidate = null; for (Method candidate : candidates) { if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) { if (uniqueCandidate == null) { uniqueCandidate = candidate; } else if (!Arrays.equals( uniqueCandidate.getParameterTypes(), candidate.getParameterTypes())) { uniqueCandidate = null; break; } } } synchronized (mbd.constructorArgumentLock) { mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate; } }
public String[] getBeanNamesForType( Class type, boolean includePrototypes, boolean includeFactoryBeans) { List result = new ArrayList(); // Check all bean definitions. for (Iterator it = this.beanDefinitionNames.iterator(); it.hasNext(); ) { String beanName = (String) it.next(); RootBeanDefinition rbd = getMergedBeanDefinition(beanName, false); // Only check bean definition if it is complete. if (!rbd.isAbstract()) { // In case of FactoryBean, match object created by FactoryBean. boolean isFactoryBean = rbd.hasBeanClass() && FactoryBean.class.isAssignableFrom(rbd.getBeanClass()); if (isFactoryBean || rbd.getFactoryBeanName() != null) { if (includeFactoryBeans && (includePrototypes || isSingleton(beanName)) && isBeanTypeMatch(beanName, type)) { result.add(beanName); // Match found for this bean: do not match FactoryBean itself anymore. continue; } // We're done for anything but a full FactoryBean. if (!isFactoryBean) { continue; } // In case of FactoryBean, try to match FactoryBean itself next. beanName = FACTORY_BEAN_PREFIX + beanName; } // Match raw bean instance (might be raw FactoryBean). if ((includePrototypes || rbd.isSingleton()) && isBeanTypeMatch(beanName, type)) { result.add(beanName); } } } // Check singletons too, to catch manually registered singletons. String[] singletonNames = getSingletonNames(); for (int i = 0; i < singletonNames.length; i++) { String beanName = singletonNames[i]; // Only check if manually registered. if (!containsBeanDefinition(beanName)) { // In case of FactoryBean, match object created by FactoryBean. if (isFactoryBean(beanName)) { if (includeFactoryBeans && (includePrototypes || isSingleton(beanName)) && isBeanTypeMatch(beanName, type)) { result.add(beanName); // Match found for this bean: do not match FactoryBean itself anymore. continue; } // In case of FactoryBean, try to match FactoryBean itself next. beanName = FACTORY_BEAN_PREFIX + beanName; } // Match raw bean instance (might be raw FactoryBean). if (isBeanTypeMatch(beanName, type)) { result.add(beanName); } } } return (String[]) result.toArray(new String[result.size()]); }
/** * Instantiate the bean using a named factory method. The method may be static, if the bean * definition parameter specifies a class, rather than a "factory-bean", or an instance variable * on a factory object itself configured using Dependency Injection. * * <p>Implementation requires iterating over the static or instance methods with the name * specified in the RootBeanDefinition (the method may be overloaded) and trying to match with the * parameters. We don't have the types attached to constructor args, so trial and error is the * only way to go here. The explicitArgs array may contain argument values passed in * programmatically via the corresponding getBean method. * * @param beanName the name of the bean * @param mbd the merged bean definition for the bean * @param explicitArgs argument values passed in programmatically via the getBean method, or * {@code null} if none (-> use constructor argument values from bean definition) * @return a BeanWrapper for the new instance */ public BeanWrapper instantiateUsingFactoryMethod( final String beanName, final RootBeanDefinition mbd, final Object[] explicitArgs) { BeanWrapperImpl bw = new BeanWrapperImpl(); this.beanFactory.initBeanWrapper(bw); Object factoryBean; Class<?> factoryClass; boolean isStatic; String factoryBeanName = mbd.getFactoryBeanName(); if (factoryBeanName != null) { if (factoryBeanName.equals(beanName)) { throw new BeanDefinitionStoreException( mbd.getResourceDescription(), beanName, "factory-bean reference points back to the same bean definition"); } factoryBean = this.beanFactory.getBean(factoryBeanName); if (factoryBean == null) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "factory-bean '" + factoryBeanName + "' (or a BeanPostProcessor involved) returned null"); } if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) { throw new IllegalStateException( "About-to-be-created singleton instance implicitly appeared " + "through the creation of the factory bean that its bean definition points to"); } factoryClass = factoryBean.getClass(); isStatic = false; } else { // It's a static factory method on the bean class. if (!mbd.hasBeanClass()) { throw new BeanDefinitionStoreException( mbd.getResourceDescription(), beanName, "bean definition declares neither a bean class nor a factory-bean reference"); } factoryBean = null; factoryClass = mbd.getBeanClass(); isStatic = true; } Method factoryMethodToUse = null; ArgumentsHolder argsHolderToUse = null; Object[] argsToUse = null; if (explicitArgs != null) { argsToUse = explicitArgs; } else { Object[] argsToResolve = null; synchronized (mbd.constructorArgumentLock) { factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod; if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) { // Found a cached factory method... argsToUse = mbd.resolvedConstructorArguments; if (argsToUse == null) { argsToResolve = mbd.preparedConstructorArguments; } } } if (argsToResolve != null) { argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve); } } if (factoryMethodToUse == null || argsToUse == null) { // Need to determine the factory method... // Try all methods with this name to see if they match the given arguments. factoryClass = ClassUtils.getUserClass(factoryClass); Method[] rawCandidates = getCandidateMethods(factoryClass, mbd); List<Method> candidateSet = new ArrayList<Method>(); for (Method candidate : rawCandidates) { if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) { candidateSet.add(candidate); } } Method[] candidates = candidateSet.toArray(new Method[candidateSet.size()]); AutowireUtils.sortFactoryMethods(candidates); ConstructorArgumentValues resolvedValues = null; boolean autowiring = (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR); int minTypeDiffWeight = Integer.MAX_VALUE; Set<Method> ambiguousFactoryMethods = null; int minNrOfArgs; if (explicitArgs != null) { minNrOfArgs = explicitArgs.length; } else { // We don't have arguments passed in programmatically, so we need to resolve the // arguments specified in the constructor arguments held in the bean definition. ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues(); resolvedValues = new ConstructorArgumentValues(); minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues); } List<Exception> causes = null; for (int i = 0; i < candidates.length; i++) { Method candidate = candidates[i]; Class<?>[] paramTypes = candidate.getParameterTypes(); if (paramTypes.length >= minNrOfArgs) { ArgumentsHolder argsHolder; if (resolvedValues != null) { // Resolved constructor arguments: type conversion and/or autowiring necessary. try { String[] paramNames = null; ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer(); if (pnd != null) { paramNames = pnd.getParameterNames(candidate); } argsHolder = createArgumentArray( beanName, mbd, resolvedValues, bw, paramTypes, paramNames, candidate, autowiring); } catch (UnsatisfiedDependencyException ex) { if (this.beanFactory.logger.isTraceEnabled()) { this.beanFactory.logger.trace( "Ignoring factory method [" + candidate + "] of bean '" + beanName + "': " + ex); } if (i == candidates.length - 1 && argsHolderToUse == null) { if (causes != null) { for (Exception cause : causes) { this.beanFactory.onSuppressedException(cause); } } throw ex; } else { // Swallow and try next overloaded factory method. if (causes == null) { causes = new LinkedList<Exception>(); } causes.add(ex); continue; } } } else { // Explicit arguments given -> arguments length must match exactly. if (paramTypes.length != explicitArgs.length) { continue; } argsHolder = new ArgumentsHolder(explicitArgs); } int typeDiffWeight = (mbd.isLenientConstructorResolution() ? argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes)); // Choose this factory method if it represents the closest match. if (typeDiffWeight < minTypeDiffWeight) { factoryMethodToUse = candidate; argsHolderToUse = argsHolder; argsToUse = argsHolder.arguments; minTypeDiffWeight = typeDiffWeight; ambiguousFactoryMethods = null; } // Find out about ambiguity: In case of the same type difference weight // for methods with the same number of parameters, collect such candidates // and eventually raise an ambiguity exception. // However, only perform that check in non-lenient constructor resolution mode, // and explicitly ignore overridden methods (with the same parameter signature). else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight && !mbd.isLenientConstructorResolution() && paramTypes.length == factoryMethodToUse.getParameterTypes().length && !Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) { if (ambiguousFactoryMethods == null) { ambiguousFactoryMethods = new LinkedHashSet<Method>(); ambiguousFactoryMethods.add(factoryMethodToUse); } ambiguousFactoryMethods.add(candidate); } } } if (factoryMethodToUse == null) { List<String> argTypes = new ArrayList<String>(minNrOfArgs); if (explicitArgs != null) { for (Object arg : explicitArgs) { argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null"); } } else { Set<ValueHolder> valueHolders = new LinkedHashSet<ValueHolder>(resolvedValues.getArgumentCount()); valueHolders.addAll(resolvedValues.getIndexedArgumentValues().values()); valueHolders.addAll(resolvedValues.getGenericArgumentValues()); for (ValueHolder value : valueHolders) { String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) : (value.getValue() != null ? value.getValue().getClass().getSimpleName() : "null")); argTypes.add(argType); } } String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes); throw new BeanCreationException( mbd.getResourceDescription(), beanName, "No matching factory method found: " + (mbd.getFactoryBeanName() != null ? "factory bean '" + mbd.getFactoryBeanName() + "'; " : "") + "factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " + "Check that a method with the specified name " + (minNrOfArgs > 0 ? "and arguments " : "") + "exists and that it is " + (isStatic ? "static" : "non-static") + "."); } else if (void.class.equals(factoryMethodToUse.getReturnType())) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Invalid factory method '" + mbd.getFactoryMethodName() + "': needs to have a non-void return type!"); } else if (ambiguousFactoryMethods != null) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Ambiguous factory method matches found in bean '" + beanName + "' " + "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " + ambiguousFactoryMethods); } if (explicitArgs == null && argsHolderToUse != null) { argsHolderToUse.storeCache(mbd, factoryMethodToUse); } } try { Object beanInstance; if (System.getSecurityManager() != null) { final Object fb = factoryBean; final Method factoryMethod = factoryMethodToUse; final Object[] args = argsToUse; beanInstance = AccessController.doPrivileged( new PrivilegedAction<Object>() { @Override public Object run() { return beanFactory .getInstantiationStrategy() .instantiate(mbd, beanName, beanFactory, fb, factoryMethod, args); } }, beanFactory.getAccessControlContext()); } else { beanInstance = this.beanFactory .getInstantiationStrategy() .instantiate( mbd, beanName, this.beanFactory, factoryBean, factoryMethodToUse, argsToUse); } if (beanInstance == null) { return null; } bw.setWrappedInstance(beanInstance); return bw; } catch (Throwable ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Bean instantiation via factory method failed", ex); } }