Detect generic type match behind interface-based proxy as well
Issue: SPR-14097
This commit is contained in:
		
							parent
							
								
									0208198804
								
							
						
					
					
						commit
						f805427629
					
				| 
						 | 
				
			
			@ -528,6 +528,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
 | 
			
		|||
		}
 | 
			
		||||
		final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
 | 
			
		||||
		Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
 | 
			
		||||
		mbd.resolvedTargetType = beanType;
 | 
			
		||||
 | 
			
		||||
		// Allow post-processors to modify the merged bean definition.
 | 
			
		||||
		synchronized (mbd.postProcessingLock) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -405,33 +405,31 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
 | 
			
		|||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		else {
 | 
			
		||||
			// No singleton instance found -> check bean definition.
 | 
			
		||||
			BeanFactory parentBeanFactory = getParentBeanFactory();
 | 
			
		||||
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
 | 
			
		||||
				// No bean definition found in this factory -> delegate to parent.
 | 
			
		||||
				return parentBeanFactory.isSingleton(originalBeanName(name));
 | 
			
		||||
			}
 | 
			
		||||
		// No singleton instance found -> check bean definition.
 | 
			
		||||
		BeanFactory parentBeanFactory = getParentBeanFactory();
 | 
			
		||||
		if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
 | 
			
		||||
			// No bean definition found in this factory -> delegate to parent.
 | 
			
		||||
			return parentBeanFactory.isSingleton(originalBeanName(name));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
			RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
 | 
			
		||||
		RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
 | 
			
		||||
 | 
			
		||||
			// In case of FactoryBean, return singleton status of created object if not a dereference.
 | 
			
		||||
			if (mbd.isSingleton()) {
 | 
			
		||||
				if (isFactoryBean(beanName, mbd)) {
 | 
			
		||||
					if (BeanFactoryUtils.isFactoryDereference(name)) {
 | 
			
		||||
						return true;
 | 
			
		||||
					}
 | 
			
		||||
					FactoryBean<?> factoryBean = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
 | 
			
		||||
					return factoryBean.isSingleton();
 | 
			
		||||
				}
 | 
			
		||||
				else {
 | 
			
		||||
					return !BeanFactoryUtils.isFactoryDereference(name);
 | 
			
		||||
		// In case of FactoryBean, return singleton status of created object if not a dereference.
 | 
			
		||||
		if (mbd.isSingleton()) {
 | 
			
		||||
			if (isFactoryBean(beanName, mbd)) {
 | 
			
		||||
				if (BeanFactoryUtils.isFactoryDereference(name)) {
 | 
			
		||||
					return true;
 | 
			
		||||
				}
 | 
			
		||||
				FactoryBean<?> factoryBean = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
 | 
			
		||||
				return factoryBean.isSingleton();
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				return false;
 | 
			
		||||
				return !BeanFactoryUtils.isFactoryDereference(name);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
| 
						 | 
				
			
			@ -449,32 +447,31 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
 | 
			
		|||
			// In case of FactoryBean, return singleton status of created object if not a dereference.
 | 
			
		||||
			return (!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(beanName, mbd));
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			// Singleton or scoped - not a prototype.
 | 
			
		||||
			// However, FactoryBean may still produce a prototype object...
 | 
			
		||||
			if (BeanFactoryUtils.isFactoryDereference(name)) {
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
			if (isFactoryBean(beanName, mbd)) {
 | 
			
		||||
				final FactoryBean<?> fb = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
 | 
			
		||||
				if (System.getSecurityManager() != null) {
 | 
			
		||||
					return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
 | 
			
		||||
						@Override
 | 
			
		||||
						public Boolean run() {
 | 
			
		||||
							return ((fb instanceof SmartFactoryBean && ((SmartFactoryBean<?>) fb).isPrototype()) ||
 | 
			
		||||
									!fb.isSingleton());
 | 
			
		||||
						}
 | 
			
		||||
					}, getAccessControlContext());
 | 
			
		||||
				}
 | 
			
		||||
				else {
 | 
			
		||||
					return ((fb instanceof SmartFactoryBean && ((SmartFactoryBean<?>) fb).isPrototype()) ||
 | 
			
		||||
							!fb.isSingleton());
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
		// Singleton or scoped - not a prototype.
 | 
			
		||||
		// However, FactoryBean may still produce a prototype object...
 | 
			
		||||
		if (BeanFactoryUtils.isFactoryDereference(name)) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		if (isFactoryBean(beanName, mbd)) {
 | 
			
		||||
			final FactoryBean<?> fb = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
 | 
			
		||||
			if (System.getSecurityManager() != null) {
 | 
			
		||||
				return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
 | 
			
		||||
					@Override
 | 
			
		||||
					public Boolean run() {
 | 
			
		||||
						return ((fb instanceof SmartFactoryBean && ((SmartFactoryBean<?>) fb).isPrototype()) ||
 | 
			
		||||
								!fb.isSingleton());
 | 
			
		||||
					}
 | 
			
		||||
				}, getAccessControlContext());
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				return false;
 | 
			
		||||
				return ((fb instanceof SmartFactoryBean && ((SmartFactoryBean<?>) fb).isPrototype()) ||
 | 
			
		||||
						!fb.isSingleton());
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
| 
						 | 
				
			
			@ -493,78 +490,91 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
 | 
			
		|||
					return typeToMatch.isInstance(beanInstance);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				return (!BeanFactoryUtils.isFactoryDereference(name) && typeToMatch.isInstance(beanInstance));
 | 
			
		||||
			else if (!BeanFactoryUtils.isFactoryDereference(name)) {
 | 
			
		||||
				if (typeToMatch.isInstance(beanInstance)) {
 | 
			
		||||
					// Direct match for exposed instance?
 | 
			
		||||
					return true;
 | 
			
		||||
				}
 | 
			
		||||
				else if (typeToMatch.hasGenerics() && containsBeanDefinition(beanName)) {
 | 
			
		||||
					// Generics potentially only match on the target class, not on the proxy...
 | 
			
		||||
					RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
 | 
			
		||||
					Class<?> targetType = mbd.getTargetType();
 | 
			
		||||
					if (targetType != null && targetType != ClassUtils.getUserClass(beanInstance) &&
 | 
			
		||||
							typeToMatch.isAssignableFrom(targetType)) {
 | 
			
		||||
						// Check raw class match as well, making sure it's exposed on the proxy.
 | 
			
		||||
						Class<?> classToMatch = typeToMatch.resolve();
 | 
			
		||||
						return (classToMatch == null || classToMatch.isInstance(beanInstance));
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		else if (containsSingleton(beanName) && !containsBeanDefinition(beanName)) {
 | 
			
		||||
			// null instance registered
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		else {
 | 
			
		||||
			// No singleton instance found -> check bean definition.
 | 
			
		||||
			BeanFactory parentBeanFactory = getParentBeanFactory();
 | 
			
		||||
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
 | 
			
		||||
				// No bean definition found in this factory -> delegate to parent.
 | 
			
		||||
				return parentBeanFactory.isTypeMatch(originalBeanName(name), typeToMatch);
 | 
			
		||||
			}
 | 
			
		||||
		// No singleton instance found -> check bean definition.
 | 
			
		||||
		BeanFactory parentBeanFactory = getParentBeanFactory();
 | 
			
		||||
		if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
 | 
			
		||||
			// No bean definition found in this factory -> delegate to parent.
 | 
			
		||||
			return parentBeanFactory.isTypeMatch(originalBeanName(name), typeToMatch);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
			// Retrieve corresponding bean definition.
 | 
			
		||||
			RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
 | 
			
		||||
		// Retrieve corresponding bean definition.
 | 
			
		||||
		RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
 | 
			
		||||
 | 
			
		||||
			Class<?> classToMatch = typeToMatch.resolve();
 | 
			
		||||
			if (classToMatch == null) {
 | 
			
		||||
				classToMatch = FactoryBean.class;
 | 
			
		||||
			}
 | 
			
		||||
			Class<?>[] typesToMatch = (FactoryBean.class == classToMatch ?
 | 
			
		||||
					new Class<?>[] {classToMatch} : new Class<?>[] {FactoryBean.class, classToMatch});
 | 
			
		||||
		Class<?> classToMatch = typeToMatch.resolve();
 | 
			
		||||
		if (classToMatch == null) {
 | 
			
		||||
			classToMatch = FactoryBean.class;
 | 
			
		||||
		}
 | 
			
		||||
		Class<?>[] typesToMatch = (FactoryBean.class == classToMatch ?
 | 
			
		||||
				new Class<?>[] {classToMatch} : new Class<?>[] {FactoryBean.class, classToMatch});
 | 
			
		||||
 | 
			
		||||
			// Check decorated bean definition, if any: We assume it'll be easier
 | 
			
		||||
			// to determine the decorated bean's type than the proxy's type.
 | 
			
		||||
			BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
 | 
			
		||||
			if (dbd != null && !BeanFactoryUtils.isFactoryDereference(name)) {
 | 
			
		||||
				RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd);
 | 
			
		||||
				Class<?> targetClass = predictBeanType(dbd.getBeanName(), tbd, typesToMatch);
 | 
			
		||||
				if (targetClass != null && !FactoryBean.class.isAssignableFrom(targetClass)) {
 | 
			
		||||
					return typeToMatch.isAssignableFrom(targetClass);
 | 
			
		||||
				}
 | 
			
		||||
		// Check decorated bean definition, if any: We assume it'll be easier
 | 
			
		||||
		// to determine the decorated bean's type than the proxy's type.
 | 
			
		||||
		BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
 | 
			
		||||
		if (dbd != null && !BeanFactoryUtils.isFactoryDereference(name)) {
 | 
			
		||||
			RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd);
 | 
			
		||||
			Class<?> targetClass = predictBeanType(dbd.getBeanName(), tbd, typesToMatch);
 | 
			
		||||
			if (targetClass != null && !FactoryBean.class.isAssignableFrom(targetClass)) {
 | 
			
		||||
				return typeToMatch.isAssignableFrom(targetClass);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
			Class<?> beanType = predictBeanType(beanName, mbd, typesToMatch);
 | 
			
		||||
			if (beanType == null) {
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
		Class<?> beanType = predictBeanType(beanName, mbd, typesToMatch);
 | 
			
		||||
		if (beanType == null) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
			// Check bean class whether we're dealing with a FactoryBean.
 | 
			
		||||
			if (FactoryBean.class.isAssignableFrom(beanType)) {
 | 
			
		||||
				if (!BeanFactoryUtils.isFactoryDereference(name)) {
 | 
			
		||||
					// If it's a FactoryBean, we want to look at what it creates, not the factory class.
 | 
			
		||||
					beanType = getTypeForFactoryBean(beanName, mbd);
 | 
			
		||||
					if (beanType == null) {
 | 
			
		||||
						return false;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			else if (BeanFactoryUtils.isFactoryDereference(name)) {
 | 
			
		||||
				// Special case: A SmartInstantiationAwareBeanPostProcessor returned a non-FactoryBean
 | 
			
		||||
				// type but we nevertheless are being asked to dereference a FactoryBean...
 | 
			
		||||
				// Let's check the original bean class and proceed with it if it is a FactoryBean.
 | 
			
		||||
				beanType = predictBeanType(beanName, mbd, FactoryBean.class);
 | 
			
		||||
				if (beanType == null || !FactoryBean.class.isAssignableFrom(beanType)) {
 | 
			
		||||
		// Check bean class whether we're dealing with a FactoryBean.
 | 
			
		||||
		if (FactoryBean.class.isAssignableFrom(beanType)) {
 | 
			
		||||
			if (!BeanFactoryUtils.isFactoryDereference(name)) {
 | 
			
		||||
				// If it's a FactoryBean, we want to look at what it creates, not the factory class.
 | 
			
		||||
				beanType = getTypeForFactoryBean(beanName, mbd);
 | 
			
		||||
				if (beanType == null) {
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			ResolvableType resolvableType = mbd.targetType;
 | 
			
		||||
			if (resolvableType == null) {
 | 
			
		||||
				resolvableType = mbd.factoryMethodReturnType;
 | 
			
		||||
			}
 | 
			
		||||
			if (resolvableType != null && resolvableType.resolve() == beanType) {
 | 
			
		||||
				return typeToMatch.isAssignableFrom(resolvableType);
 | 
			
		||||
			}
 | 
			
		||||
			return typeToMatch.isAssignableFrom(beanType);
 | 
			
		||||
		}
 | 
			
		||||
		else if (BeanFactoryUtils.isFactoryDereference(name)) {
 | 
			
		||||
			// Special case: A SmartInstantiationAwareBeanPostProcessor returned a non-FactoryBean
 | 
			
		||||
			// type but we nevertheless are being asked to dereference a FactoryBean...
 | 
			
		||||
			// Let's check the original bean class and proceed with it if it is a FactoryBean.
 | 
			
		||||
			beanType = predictBeanType(beanName, mbd, FactoryBean.class);
 | 
			
		||||
			if (beanType == null || !FactoryBean.class.isAssignableFrom(beanType)) {
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ResolvableType resolvableType = mbd.targetType;
 | 
			
		||||
		if (resolvableType == null) {
 | 
			
		||||
			resolvableType = mbd.factoryMethodReturnType;
 | 
			
		||||
		}
 | 
			
		||||
		if (resolvableType != null && resolvableType.resolve() == beanType) {
 | 
			
		||||
			return typeToMatch.isAssignableFrom(resolvableType);
 | 
			
		||||
		}
 | 
			
		||||
		return typeToMatch.isAssignableFrom(beanType);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
| 
						 | 
				
			
			@ -591,43 +601,41 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
 | 
			
		|||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		else {
 | 
			
		||||
			// No singleton instance found -> check bean definition.
 | 
			
		||||
			BeanFactory parentBeanFactory = getParentBeanFactory();
 | 
			
		||||
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
 | 
			
		||||
				// No bean definition found in this factory -> delegate to parent.
 | 
			
		||||
				return parentBeanFactory.getType(originalBeanName(name));
 | 
			
		||||
		// No singleton instance found -> check bean definition.
 | 
			
		||||
		BeanFactory parentBeanFactory = getParentBeanFactory();
 | 
			
		||||
		if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
 | 
			
		||||
			// No bean definition found in this factory -> delegate to parent.
 | 
			
		||||
			return parentBeanFactory.getType(originalBeanName(name));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
 | 
			
		||||
 | 
			
		||||
		// Check decorated bean definition, if any: We assume it'll be easier
 | 
			
		||||
		// to determine the decorated bean's type than the proxy's type.
 | 
			
		||||
		BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
 | 
			
		||||
		if (dbd != null && !BeanFactoryUtils.isFactoryDereference(name)) {
 | 
			
		||||
			RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd);
 | 
			
		||||
			Class<?> targetClass = predictBeanType(dbd.getBeanName(), tbd);
 | 
			
		||||
			if (targetClass != null && !FactoryBean.class.isAssignableFrom(targetClass)) {
 | 
			
		||||
				return targetClass;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
			RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
 | 
			
		||||
		Class<?> beanClass = predictBeanType(beanName, mbd);
 | 
			
		||||
 | 
			
		||||
			// Check decorated bean definition, if any: We assume it'll be easier
 | 
			
		||||
			// to determine the decorated bean's type than the proxy's type.
 | 
			
		||||
			BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
 | 
			
		||||
			if (dbd != null && !BeanFactoryUtils.isFactoryDereference(name)) {
 | 
			
		||||
				RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd);
 | 
			
		||||
				Class<?> targetClass = predictBeanType(dbd.getBeanName(), tbd);
 | 
			
		||||
				if (targetClass != null && !FactoryBean.class.isAssignableFrom(targetClass)) {
 | 
			
		||||
					return targetClass;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			Class<?> beanClass = predictBeanType(beanName, mbd);
 | 
			
		||||
 | 
			
		||||
			// Check bean class whether we're dealing with a FactoryBean.
 | 
			
		||||
			if (beanClass != null && FactoryBean.class.isAssignableFrom(beanClass)) {
 | 
			
		||||
				if (!BeanFactoryUtils.isFactoryDereference(name)) {
 | 
			
		||||
					// If it's a FactoryBean, we want to look at what it creates, not at the factory class.
 | 
			
		||||
					return getTypeForFactoryBean(beanName, mbd);
 | 
			
		||||
				}
 | 
			
		||||
				else {
 | 
			
		||||
					return beanClass;
 | 
			
		||||
				}
 | 
			
		||||
		// Check bean class whether we're dealing with a FactoryBean.
 | 
			
		||||
		if (beanClass != null && FactoryBean.class.isAssignableFrom(beanClass)) {
 | 
			
		||||
			if (!BeanFactoryUtils.isFactoryDereference(name)) {
 | 
			
		||||
				// If it's a FactoryBean, we want to look at what it creates, not at the factory class.
 | 
			
		||||
				return getTypeForFactoryBean(beanName, mbd);
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				return (!BeanFactoryUtils.isFactoryDereference(name) ? beanClass : null);
 | 
			
		||||
				return beanClass;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			return (!BeanFactoryUtils.isFactoryDereference(name) ? beanClass : null);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,9 +26,12 @@ import javax.annotation.PostConstruct;
 | 
			
		|||
import org.junit.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
 | 
			
		||||
import org.springframework.aop.interceptor.SimpleTraceInterceptor;
 | 
			
		||||
import org.springframework.aop.scope.ScopedObject;
 | 
			
		||||
import org.springframework.aop.scope.ScopedProxyUtils;
 | 
			
		||||
import org.springframework.aop.support.AopUtils;
 | 
			
		||||
import org.springframework.aop.support.DefaultPointcutAdvisor;
 | 
			
		||||
import org.springframework.beans.factory.BeanCreationException;
 | 
			
		||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
 | 
			
		||||
import org.springframework.beans.factory.FactoryBean;
 | 
			
		||||
| 
						 | 
				
			
			@ -524,6 +527,19 @@ public class ConfigurationClassPostProcessorTests {
 | 
			
		|||
		assertSame(beanFactory.getBean("genericRepo"), beanFactory.getBean("repoConsumer"));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void genericsBasedInjectionWithEarlyGenericsMatching() {
 | 
			
		||||
		beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RepositoryConfiguration.class));
 | 
			
		||||
		new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
 | 
			
		||||
 | 
			
		||||
		String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
 | 
			
		||||
		assertTrue(ObjectUtils.containsElement(beanNames, "stringRepo"));
 | 
			
		||||
 | 
			
		||||
		beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
 | 
			
		||||
		assertEquals(1, beanNames.length);
 | 
			
		||||
		assertEquals("stringRepo", beanNames[0]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void genericsBasedInjectionWithLateGenericsMatching() {
 | 
			
		||||
		beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RepositoryConfiguration.class));
 | 
			
		||||
| 
						 | 
				
			
			@ -539,9 +555,14 @@ public class ConfigurationClassPostProcessorTests {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void genericsBasedInjectionWithEarlyGenericsMatching() {
 | 
			
		||||
	public void genericsBasedInjectionWithEarlyGenericsMatchingOnCglibProxy() {
 | 
			
		||||
		beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RepositoryConfiguration.class));
 | 
			
		||||
		new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
 | 
			
		||||
		DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
 | 
			
		||||
		autoProxyCreator.setProxyTargetClass(true);
 | 
			
		||||
		autoProxyCreator.setBeanFactory(beanFactory);
 | 
			
		||||
		beanFactory.addBeanPostProcessor(autoProxyCreator);
 | 
			
		||||
		beanFactory.registerSingleton("traceInterceptor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor()));
 | 
			
		||||
 | 
			
		||||
		String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
 | 
			
		||||
		assertTrue(ObjectUtils.containsElement(beanNames, "stringRepo"));
 | 
			
		||||
| 
						 | 
				
			
			@ -549,6 +570,109 @@ public class ConfigurationClassPostProcessorTests {
 | 
			
		|||
		beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
 | 
			
		||||
		assertEquals(1, beanNames.length);
 | 
			
		||||
		assertEquals("stringRepo", beanNames[0]);
 | 
			
		||||
 | 
			
		||||
		assertTrue(AopUtils.isCglibProxy(beanFactory.getBean("stringRepo")));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void genericsBasedInjectionWithLateGenericsMatchingOnCglibProxy() {
 | 
			
		||||
		beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RepositoryConfiguration.class));
 | 
			
		||||
		new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
 | 
			
		||||
		DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
 | 
			
		||||
		autoProxyCreator.setProxyTargetClass(true);
 | 
			
		||||
		autoProxyCreator.setBeanFactory(beanFactory);
 | 
			
		||||
		beanFactory.addBeanPostProcessor(autoProxyCreator);
 | 
			
		||||
		beanFactory.registerSingleton("traceInterceptor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor()));
 | 
			
		||||
		beanFactory.preInstantiateSingletons();
 | 
			
		||||
 | 
			
		||||
		String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
 | 
			
		||||
		assertTrue(ObjectUtils.containsElement(beanNames, "stringRepo"));
 | 
			
		||||
 | 
			
		||||
		beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
 | 
			
		||||
		assertEquals(1, beanNames.length);
 | 
			
		||||
		assertEquals("stringRepo", beanNames[0]);
 | 
			
		||||
 | 
			
		||||
		assertTrue(AopUtils.isCglibProxy(beanFactory.getBean("stringRepo")));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void genericsBasedInjectionWithLateGenericsMatchingOnCglibProxyAndRawFactoryMethod() {
 | 
			
		||||
		beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawRepositoryConfiguration.class));
 | 
			
		||||
		new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
 | 
			
		||||
		DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
 | 
			
		||||
		autoProxyCreator.setProxyTargetClass(true);
 | 
			
		||||
		autoProxyCreator.setBeanFactory(beanFactory);
 | 
			
		||||
		beanFactory.addBeanPostProcessor(autoProxyCreator);
 | 
			
		||||
		beanFactory.registerSingleton("traceInterceptor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor()));
 | 
			
		||||
		beanFactory.preInstantiateSingletons();
 | 
			
		||||
 | 
			
		||||
		String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
 | 
			
		||||
		assertTrue(ObjectUtils.containsElement(beanNames, "stringRepo"));
 | 
			
		||||
 | 
			
		||||
		beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
 | 
			
		||||
		assertEquals(1, beanNames.length);
 | 
			
		||||
		assertEquals("stringRepo", beanNames[0]);
 | 
			
		||||
 | 
			
		||||
		assertTrue(AopUtils.isCglibProxy(beanFactory.getBean("stringRepo")));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void genericsBasedInjectionWithEarlyGenericsMatchingOnJdkProxy() {
 | 
			
		||||
		beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RepositoryConfiguration.class));
 | 
			
		||||
		new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
 | 
			
		||||
		DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
 | 
			
		||||
		autoProxyCreator.setBeanFactory(beanFactory);
 | 
			
		||||
		beanFactory.addBeanPostProcessor(autoProxyCreator);
 | 
			
		||||
		beanFactory.registerSingleton("traceInterceptor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor()));
 | 
			
		||||
 | 
			
		||||
		String[] beanNames = beanFactory.getBeanNamesForType(RepositoryInterface.class);
 | 
			
		||||
		assertTrue(ObjectUtils.containsElement(beanNames, "stringRepo"));
 | 
			
		||||
 | 
			
		||||
		beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(RepositoryInterface.class, String.class));
 | 
			
		||||
		assertEquals(1, beanNames.length);
 | 
			
		||||
		assertEquals("stringRepo", beanNames[0]);
 | 
			
		||||
 | 
			
		||||
		assertTrue(AopUtils.isJdkDynamicProxy(beanFactory.getBean("stringRepo")));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void genericsBasedInjectionWithLateGenericsMatchingOnJdkProxy() {
 | 
			
		||||
		beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RepositoryConfiguration.class));
 | 
			
		||||
		new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
 | 
			
		||||
		DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
 | 
			
		||||
		autoProxyCreator.setBeanFactory(beanFactory);
 | 
			
		||||
		beanFactory.addBeanPostProcessor(autoProxyCreator);
 | 
			
		||||
		beanFactory.registerSingleton("traceInterceptor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor()));
 | 
			
		||||
		beanFactory.preInstantiateSingletons();
 | 
			
		||||
 | 
			
		||||
		String[] beanNames = beanFactory.getBeanNamesForType(RepositoryInterface.class);
 | 
			
		||||
		assertTrue(ObjectUtils.containsElement(beanNames, "stringRepo"));
 | 
			
		||||
 | 
			
		||||
		beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(RepositoryInterface.class, String.class));
 | 
			
		||||
		assertEquals(1, beanNames.length);
 | 
			
		||||
		assertEquals("stringRepo", beanNames[0]);
 | 
			
		||||
 | 
			
		||||
		assertTrue(AopUtils.isJdkDynamicProxy(beanFactory.getBean("stringRepo")));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void genericsBasedInjectionWithLateGenericsMatchingOnJdkProxyAndRawFactoryMethod() {
 | 
			
		||||
		beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawRepositoryConfiguration.class));
 | 
			
		||||
		new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
 | 
			
		||||
		DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
 | 
			
		||||
		autoProxyCreator.setBeanFactory(beanFactory);
 | 
			
		||||
		beanFactory.addBeanPostProcessor(autoProxyCreator);
 | 
			
		||||
		beanFactory.registerSingleton("traceInterceptor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor()));
 | 
			
		||||
		beanFactory.preInstantiateSingletons();
 | 
			
		||||
 | 
			
		||||
		String[] beanNames = beanFactory.getBeanNamesForType(RepositoryInterface.class);
 | 
			
		||||
		assertTrue(ObjectUtils.containsElement(beanNames, "stringRepo"));
 | 
			
		||||
 | 
			
		||||
		beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(RepositoryInterface.class, String.class));
 | 
			
		||||
		assertEquals(1, beanNames.length);
 | 
			
		||||
		assertEquals("stringRepo", beanNames[0]);
 | 
			
		||||
 | 
			
		||||
		assertTrue(AopUtils.isJdkDynamicProxy(beanFactory.getBean("stringRepo")));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
| 
						 | 
				
			
			@ -752,7 +876,12 @@ public class ConfigurationClassPostProcessorTests {
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static class Repository<T> {
 | 
			
		||||
	public interface RepositoryInterface<T> {
 | 
			
		||||
 | 
			
		||||
		String toString();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static class Repository<T> implements RepositoryInterface<T> {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static class GenericRepository<T> extends Repository<T> {
 | 
			
		||||
| 
						 | 
				
			
			@ -819,6 +948,21 @@ public class ConfigurationClassPostProcessorTests {
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	@Configuration
 | 
			
		||||
	public static class RawRepositoryConfiguration {
 | 
			
		||||
 | 
			
		||||
		@Bean
 | 
			
		||||
		public Repository stringRepo() {
 | 
			
		||||
			return new Repository<String>() {
 | 
			
		||||
				@Override
 | 
			
		||||
				public String toString() {
 | 
			
		||||
					return "Repository<String>";
 | 
			
		||||
				}
 | 
			
		||||
			};
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Configuration
 | 
			
		||||
	public static class ScopedRepositoryConfiguration {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -624,19 +624,19 @@ public class ResolvableType implements Serializable {
 | 
			
		|||
	 * @see #resolveGenerics()
 | 
			
		||||
	 */
 | 
			
		||||
	public ResolvableType getGeneric(int... indexes) {
 | 
			
		||||
		try {
 | 
			
		||||
			if (indexes == null || indexes.length == 0) {
 | 
			
		||||
				return getGenerics()[0];
 | 
			
		||||
			}
 | 
			
		||||
			ResolvableType generic = this;
 | 
			
		||||
			for (int index : indexes) {
 | 
			
		||||
				generic = generic.getGenerics()[index];
 | 
			
		||||
			}
 | 
			
		||||
			return generic;
 | 
			
		||||
		ResolvableType[] generics = getGenerics();
 | 
			
		||||
		if (indexes == null || indexes.length == 0) {
 | 
			
		||||
			return (generics.length == 0 ? NONE : generics[0]);
 | 
			
		||||
		}
 | 
			
		||||
		catch (IndexOutOfBoundsException ex) {
 | 
			
		||||
			return NONE;
 | 
			
		||||
		ResolvableType generic = this;
 | 
			
		||||
		for (int index : indexes) {
 | 
			
		||||
			generics = generic.getGenerics();
 | 
			
		||||
			if (index < 0 || index >= generics.length) {
 | 
			
		||||
				return NONE;
 | 
			
		||||
			}
 | 
			
		||||
			generic = generics[index];
 | 
			
		||||
		}
 | 
			
		||||
		return generic;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -947,6 +947,10 @@ public class ResolvableType implements Serializable {
 | 
			
		|||
	 */
 | 
			
		||||
	public static ResolvableType forRawClass(Class<?> clazz) {
 | 
			
		||||
		return new ResolvableType(clazz) {
 | 
			
		||||
			@Override
 | 
			
		||||
			public ResolvableType[] getGenerics() {
 | 
			
		||||
				return EMPTY_TYPES_ARRAY;
 | 
			
		||||
			}
 | 
			
		||||
			@Override
 | 
			
		||||
			public boolean isAssignableFrom(Class<?> other) {
 | 
			
		||||
				return ClassUtils.isAssignable(getRawClass(), other);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue