diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/NoSuchBeanDefinitionException.java b/spring-beans/src/main/java/org/springframework/beans/factory/NoSuchBeanDefinitionException.java index 31d2cfbe3bb..c02210581b6 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/NoSuchBeanDefinitionException.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/NoSuchBeanDefinitionException.java @@ -127,7 +127,7 @@ public class NoSuchBeanDefinitionException extends BeansException { * that failed. */ public Class> getBeanType() { - return (this.resolvableType != null ? this.resolvableType.getRawClass() : null); + return (this.resolvableType != null ? this.resolvableType.resolve() : null); } /** diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java index 69b3d93a062..1884912e652 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java @@ -74,6 +74,7 @@ import org.springframework.core.GenericTypeResolver; import org.springframework.core.MethodParameter; import org.springframework.core.ParameterNameDiscoverer; import org.springframework.core.PriorityOrdered; +import org.springframework.core.ResolvableType; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; import org.springframework.util.ReflectionUtils; @@ -659,9 +660,9 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac * @see #createBean */ protected Class> getTypeForFactoryMethod(String beanName, RootBeanDefinition mbd, Class>... typesToMatch) { - Class> preResolved = mbd.resolvedFactoryMethodReturnType; - if (preResolved != null) { - return preResolved; + ResolvableType cachedReturnType = mbd.factoryMethodReturnType; + if (cachedReturnType != null) { + return cachedReturnType.resolve(); } Class> factoryClass; @@ -685,11 +686,12 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac 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; - boolean cache = false; + Method uniqueCandidate = null; int minNrOfArgs = mbd.getConstructorArgumentValues().getArgumentCount(); Method[] candidates = ReflectionUtils.getUniqueDeclaredMethods(factoryClass); for (Method factoryMethod : candidates) { @@ -724,8 +726,12 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac Class> returnType = AutowireUtils.resolveReturnTypeForFactoryMethod( factoryMethod, args, getBeanClassLoader()); if (returnType != null) { - cache = true; + uniqueCandidate = (commonType == null ? factoryMethod : null); commonType = ClassUtils.determineCommonAncestor(returnType, commonType); + if (commonType == null) { + // Ambiguous return types found: return null to indicate "not determinable". + return null; + } } } catch (Throwable ex) { @@ -735,22 +741,22 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac } } else { + uniqueCandidate = (commonType == null ? factoryMethod : null); commonType = ClassUtils.determineCommonAncestor(factoryMethod.getReturnType(), commonType); + if (commonType == null) { + // Ambiguous return types found: return null to indicate "not determinable". + return null; + } } } } if (commonType != null) { // Clear return type found: all factory methods return same type. - if (cache) { - mbd.resolvedFactoryMethodReturnType = commonType; - } - return commonType; - } - else { - // Ambiguous return types found: return null to indicate "not determinable". - return null; + mbd.factoryMethodReturnType = (uniqueCandidate != null ? + ResolvableType.forMethodReturnType(uniqueCandidate) : ResolvableType.forClass(commonType)); } + return commonType; } /** diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java index 6b034851b38..326c3295be0 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java @@ -517,7 +517,10 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp // Retrieve corresponding bean definition. RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); - Class> classToMatch = typeToMatch.getRawClass(); + Class> classToMatch = typeToMatch.resolve(); + if (classToMatch == null) { + classToMatch = FactoryBean.class; + } Class>[] typesToMatch = (FactoryBean.class == classToMatch ? new Class>[] {classToMatch} : new Class>[] {FactoryBean.class, classToMatch}); @@ -557,6 +560,13 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp } } + ResolvableType resolvableType = mbd.targetType; + if (resolvableType == null) { + resolvableType = mbd.factoryMethodReturnType; + } + if (resolvableType != null && resolvableType.resolve() == beanType) { + return typeToMatch.isAssignableFrom(resolvableType); + } return typeToMatch.isAssignableFrom(beanType); } } @@ -1447,6 +1457,10 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp * @return the type of the bean, or {@code null} if not predictable */ protected Class> predictBeanType(String beanName, RootBeanDefinition mbd, Class>... typesToMatch) { + Class> targetType = mbd.getTargetType(); + if (targetType != null) { + return targetType; + } if (mbd.getFactoryMethodName() != null) { return null; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireUtils.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireUtils.java index 1bf54034558..0b650df8232 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireUtils.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -162,8 +162,8 @@ abstract class AutowireUtils { * Determine the target type for the generic return type of the given * generic factory method, where formal type variables are declared * on the given method itself. - *
For example, given a factory method with the following signature, - * if {@code resolveReturnTypeForFactoryMethod()} is invoked with the reflected + *
For example, given a factory method with the following signature, if
+ * {@code resolveReturnTypeForFactoryMethod()} is invoked with the reflected
* method for {@code creatProxy()} and an {@code Object[]} array containing
* {@code MyService.class}, {@code resolveReturnTypeForFactoryMethod()} will
* infer that the target return type is {@code MyService}.
@@ -184,9 +184,9 @@ abstract class AutowireUtils {
* @param method the method to introspect (never {@code null})
* @param args the arguments that will be supplied to the method when it is
* invoked (never {@code null})
- * @param classLoader the ClassLoader to resolve class names against, if necessary
- * (never {@code null})
- * @return the resolved target return type, the standard return type, or {@code null}
+ * @param classLoader the ClassLoader to resolve class names against,
+ * if necessary (never {@code null})
+ * @return the resolved target return type or the standard method return type
* @since 3.2.5
*/
public static Class> resolveReturnTypeForFactoryMethod(Method method, Object[] args, ClassLoader classLoader) {
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/GenericTypeAwareAutowireCandidateResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/GenericTypeAwareAutowireCandidateResolver.java
index cba9e9770ab..b204d551c3c 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/GenericTypeAwareAutowireCandidateResolver.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/GenericTypeAwareAutowireCandidateResolver.java
@@ -147,22 +147,23 @@ public class GenericTypeAwareAutowireCandidateResolver implements AutowireCandid
protected ResolvableType getReturnTypeForFactoryMethod(RootBeanDefinition rbd, DependencyDescriptor descriptor) {
// Should typically be set for any kind of factory method, since the BeanFactory
// pre-resolves them before reaching out to the AutowireCandidateResolver...
- Class> preResolved = rbd.resolvedFactoryMethodReturnType;
- if (preResolved != null) {
- return ResolvableType.forClass(preResolved);
+ ResolvableType returnType = rbd.factoryMethodReturnType;
+ if (returnType == null) {
+ Method factoryMethod = rbd.getResolvedFactoryMethod();
+ if (factoryMethod != null) {
+ returnType = ResolvableType.forMethodReturnType(factoryMethod);
+ }
}
- else {
- Method resolvedFactoryMethod = rbd.getResolvedFactoryMethod();
- if (resolvedFactoryMethod != null) {
- if (descriptor.getDependencyType().isAssignableFrom(resolvedFactoryMethod.getReturnType())) {
- // Only use factory method metadata if the return type is actually expressive enough
- // for our dependency. Otherwise, the returned instance type may have matched instead
- // in case of a singleton instance having been registered with the container already.
- return ResolvableType.forMethodReturnType(resolvedFactoryMethod);
- }
+ if (returnType != null) {
+ Class> resolvedClass = returnType.resolve();
+ if (resolvedClass != null && descriptor.getDependencyType().isAssignableFrom(resolvedClass)) {
+ // Only use factory method metadata if the return type is actually expressive enough
+ // for our dependency. Otherwise, the returned instance type may have matched instead
+ // in case of a singleton instance having been registered with the container already.
+ return returnType;
}
- return null;
}
+ return null;
}
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java
index 237e672a3ef..6f61186a2c1 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java
@@ -64,7 +64,7 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
volatile Class> resolvedTargetType;
/** Package-visible field for caching the return type of a generically typed factory method */
- volatile Class> resolvedFactoryMethodReturnType;
+ volatile ResolvableType factoryMethodReturnType;
/** Common lock for the four constructor fields below */
final Object constructorArgumentLock = new Object();
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java
index 32866846dee..d1aa847fe0c 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java
@@ -248,7 +248,13 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
@Override
public String[] getBeanNamesForType(ResolvableType type) {
- boolean isFactoryType = (type != null && FactoryBean.class.isAssignableFrom(type.getRawClass()));
+ boolean isFactoryType = false;
+ if (type != null) {
+ Class> resolved = type.resolve();
+ if (resolved != null && FactoryBean.class.isAssignableFrom(resolved)) {
+ isFactoryType = true;
+ }
+ }
List