List of usage examples for org.springframework.beans.factory.support AutowireUtils resolveReturnTypeForFactoryMethod
public static Class<?> resolveReturnTypeForFactoryMethod(Method method, Object[] args, @Nullable ClassLoader classLoader)
From source file:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.java
/** * Determine the target type for the given bean definition which is based on * a factory method. Only called if there is no singleton instance registered * for the target bean already./* w w w . j av a 2 s .c om*/ * <p>This implementation determines the type matching {@link #createBean}'s * different creation strategies. As far as possible, we'll perform static * type checking to avoid creation of the target bean. * @param beanName the name of the bean (for error handling purposes) * @param mbd the merged bean definition for the bean * @param typesToMatch the types to match in case of internal type matching purposes * (also signals that the returned {@code Class} will never be exposed to application code) * @return the type for the bean if determinable, or {@code null} otherwise * @see #createBean */ @Nullable protected Class<?> getTypeForFactoryMethod(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) { ResolvableType cachedReturnType = mbd.factoryMethodReturnType; if (cachedReturnType != null) { return cachedReturnType.resolve(); } Class<?> factoryClass; boolean isStatic = true; 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"); } // Check declared factory method return type on factory class. factoryClass = getType(factoryBeanName); isStatic = false; } else { // Check declared factory method return type on bean class. factoryClass = resolveBeanClass(mbd, beanName, typesToMatch); } if (factoryClass == null) { return null; } factoryClass = ClassUtils.getUserClass(factoryClass); // If all factory methods have the same return type, return that type. // Can't clearly figure out exact method due to type converting / autowiring! Class<?> commonType = null; Method uniqueCandidate = null; int minNrOfArgs = (mbd.hasConstructorArgumentValues() ? mbd.getConstructorArgumentValues().getArgumentCount() : 0); Method[] candidates = this.factoryMethodCandidateCache.computeIfAbsent(factoryClass, ReflectionUtils::getUniqueDeclaredMethods); for (Method candidate : candidates) { if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate) && candidate.getParameterCount() >= minNrOfArgs) { // Declared type variables to inspect? if (candidate.getTypeParameters().length > 0) { try { // Fully resolve parameter names and argument values. Class<?>[] paramTypes = candidate.getParameterTypes(); String[] paramNames = null; ParameterNameDiscoverer pnd = getParameterNameDiscoverer(); if (pnd != null) { paramNames = pnd.getParameterNames(candidate); } ConstructorArgumentValues cav = mbd.getConstructorArgumentValues(); Set<ConstructorArgumentValues.ValueHolder> usedValueHolders = new HashSet<>( paramTypes.length); Object[] args = new Object[paramTypes.length]; for (int i = 0; i < args.length; i++) { ConstructorArgumentValues.ValueHolder valueHolder = cav.getArgumentValue(i, paramTypes[i], (paramNames != null ? paramNames[i] : null), usedValueHolders); if (valueHolder == null) { valueHolder = cav.getGenericArgumentValue(null, null, usedValueHolders); } if (valueHolder != null) { args[i] = valueHolder.getValue(); usedValueHolders.add(valueHolder); } } Class<?> returnType = AutowireUtils.resolveReturnTypeForFactoryMethod(candidate, args, getBeanClassLoader()); uniqueCandidate = (commonType == null && returnType == candidate.getReturnType() ? candidate : null); commonType = ClassUtils.determineCommonAncestor(returnType, commonType); if (commonType == null) { // Ambiguous return types found: return null to indicate "not determinable". return null; } } catch (Throwable ex) { if (logger.isDebugEnabled()) { logger.debug("Failed to resolve generic return type for factory method: " + ex); } } } else { uniqueCandidate = (commonType == null ? candidate : null); commonType = ClassUtils.determineCommonAncestor(candidate.getReturnType(), commonType); if (commonType == null) { // Ambiguous return types found: return null to indicate "not determinable". return null; } } } } if (commonType == null) { return null; } // Common return type found: all factory methods return same type. For a non-parameterized // unique candidate, cache the full type declaration context of the target factory method. cachedReturnType = (uniqueCandidate != null ? ResolvableType.forMethodReturnType(uniqueCandidate) : ResolvableType.forClass(commonType)); mbd.factoryMethodReturnType = cachedReturnType; return cachedReturnType.resolve(); }