ResolvableType-based matching respects generic factory method return type
Includes consistent use of ResolvableType.resolve() wherever applicable. Issue: SPR-15011
This commit is contained in:
@@ -109,7 +109,7 @@ public class NoSuchBeanDefinitionException extends BeansException {
|
|||||||
* that failed.
|
* that failed.
|
||||||
*/
|
*/
|
||||||
public Class<?> getBeanType() {
|
public Class<?> getBeanType() {
|
||||||
return (this.resolvableType != null ? this.resolvableType.getRawClass() : null);
|
return (this.resolvableType != null ? this.resolvableType.resolve() : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ import org.springframework.core.GenericTypeResolver;
|
|||||||
import org.springframework.core.MethodParameter;
|
import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.core.ParameterNameDiscoverer;
|
import org.springframework.core.ParameterNameDiscoverer;
|
||||||
import org.springframework.core.PriorityOrdered;
|
import org.springframework.core.PriorityOrdered;
|
||||||
|
import org.springframework.core.ResolvableType;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
@@ -672,9 +673,9 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
|||||||
* @see #createBean
|
* @see #createBean
|
||||||
*/
|
*/
|
||||||
protected Class<?> getTypeForFactoryMethod(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
|
protected Class<?> getTypeForFactoryMethod(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
|
||||||
Class<?> preResolved = mbd.resolvedFactoryMethodReturnType;
|
ResolvableType cachedReturnType = mbd.factoryMethodReturnType;
|
||||||
if (preResolved != null) {
|
if (cachedReturnType != null) {
|
||||||
return preResolved;
|
return cachedReturnType.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
Class<?> factoryClass;
|
Class<?> factoryClass;
|
||||||
@@ -698,11 +699,12 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
|||||||
if (factoryClass == null) {
|
if (factoryClass == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
factoryClass = ClassUtils.getUserClass(factoryClass);
|
||||||
|
|
||||||
// If all factory methods have the same return type, return that type.
|
// If all factory methods have the same return type, return that type.
|
||||||
// Can't clearly figure out exact method due to type converting / autowiring!
|
// Can't clearly figure out exact method due to type converting / autowiring!
|
||||||
Class<?> commonType = null;
|
Class<?> commonType = null;
|
||||||
boolean cache = false;
|
Method uniqueCandidate = null;
|
||||||
int minNrOfArgs = mbd.getConstructorArgumentValues().getArgumentCount();
|
int minNrOfArgs = mbd.getConstructorArgumentValues().getArgumentCount();
|
||||||
Method[] candidates = ReflectionUtils.getUniqueDeclaredMethods(factoryClass);
|
Method[] candidates = ReflectionUtils.getUniqueDeclaredMethods(factoryClass);
|
||||||
for (Method factoryMethod : candidates) {
|
for (Method factoryMethod : candidates) {
|
||||||
@@ -736,8 +738,12 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
|||||||
Class<?> returnType = AutowireUtils.resolveReturnTypeForFactoryMethod(
|
Class<?> returnType = AutowireUtils.resolveReturnTypeForFactoryMethod(
|
||||||
factoryMethod, args, getBeanClassLoader());
|
factoryMethod, args, getBeanClassLoader());
|
||||||
if (returnType != null) {
|
if (returnType != null) {
|
||||||
cache = true;
|
uniqueCandidate = (commonType == null ? factoryMethod : null);
|
||||||
commonType = ClassUtils.determineCommonAncestor(returnType, commonType);
|
commonType = ClassUtils.determineCommonAncestor(returnType, commonType);
|
||||||
|
if (commonType == null) {
|
||||||
|
// Ambiguous return types found: return null to indicate "not determinable".
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Throwable ex) {
|
catch (Throwable ex) {
|
||||||
@@ -747,22 +753,22 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
uniqueCandidate = (commonType == null ? factoryMethod : null);
|
||||||
commonType = ClassUtils.determineCommonAncestor(factoryMethod.getReturnType(), commonType);
|
commonType = ClassUtils.determineCommonAncestor(factoryMethod.getReturnType(), commonType);
|
||||||
|
if (commonType == null) {
|
||||||
|
// Ambiguous return types found: return null to indicate "not determinable".
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (commonType != null) {
|
if (commonType != null) {
|
||||||
// Clear return type found: all factory methods return same type.
|
// Clear return type found: all factory methods return same type.
|
||||||
if (cache) {
|
mbd.factoryMethodReturnType = (uniqueCandidate != null ?
|
||||||
mbd.resolvedFactoryMethodReturnType = commonType;
|
ResolvableType.forMethodReturnType(uniqueCandidate) : ResolvableType.forClass(commonType));
|
||||||
}
|
|
||||||
return commonType;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Ambiguous return types found: return null to indicate "not determinable".
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return commonType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -513,7 +513,10 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
|||||||
// Retrieve corresponding bean definition.
|
// Retrieve corresponding bean definition.
|
||||||
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
|
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
|
||||||
|
|
||||||
Class<?> classToMatch = typeToMatch.getRawClass();
|
Class<?> classToMatch = typeToMatch.resolve();
|
||||||
|
if (classToMatch == null) {
|
||||||
|
classToMatch = FactoryBean.class;
|
||||||
|
}
|
||||||
Class<?>[] typesToMatch = (FactoryBean.class == classToMatch ?
|
Class<?>[] typesToMatch = (FactoryBean.class == classToMatch ?
|
||||||
new Class<?>[] {classToMatch} : new Class<?>[] {FactoryBean.class, classToMatch});
|
new Class<?>[] {classToMatch} : new Class<?>[] {FactoryBean.class, classToMatch});
|
||||||
|
|
||||||
@@ -553,6 +556,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);
|
return typeToMatch.isAssignableFrom(beanType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1443,6 +1453,10 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
|||||||
* @return the type of the bean, or {@code null} if not predictable
|
* @return the type of the bean, or {@code null} if not predictable
|
||||||
*/
|
*/
|
||||||
protected Class<?> predictBeanType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
|
protected Class<?> predictBeanType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
|
||||||
|
Class<?> targetType = mbd.getTargetType();
|
||||||
|
if (targetType != null) {
|
||||||
|
return targetType;
|
||||||
|
}
|
||||||
if (mbd.getFactoryMethodName() != null) {
|
if (mbd.getFactoryMethodName() != null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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
|
* Determine the target type for the generic return type of the given
|
||||||
* <em>generic factory method</em>, where formal type variables are declared
|
* <em>generic factory method</em>, where formal type variables are declared
|
||||||
* on the given method itself.
|
* on the given method itself.
|
||||||
* <p>For example, given a factory method with the following signature,
|
* <p>For example, given a factory method with the following signature, if
|
||||||
* if {@code resolveReturnTypeForFactoryMethod()} is invoked with the reflected
|
* {@code resolveReturnTypeForFactoryMethod()} is invoked with the reflected
|
||||||
* method for {@code creatProxy()} and an {@code Object[]} array containing
|
* method for {@code creatProxy()} and an {@code Object[]} array containing
|
||||||
* {@code MyService.class}, {@code resolveReturnTypeForFactoryMethod()} will
|
* {@code MyService.class}, {@code resolveReturnTypeForFactoryMethod()} will
|
||||||
* infer that the target return type is {@code MyService}.
|
* 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 method the method to introspect (never {@code null})
|
||||||
* @param args the arguments that will be supplied to the method when it is
|
* @param args the arguments that will be supplied to the method when it is
|
||||||
* invoked (never {@code null})
|
* invoked (never {@code null})
|
||||||
* @param classLoader the ClassLoader to resolve class names against, if necessary
|
* @param classLoader the ClassLoader to resolve class names against,
|
||||||
* (never {@code null})
|
* if necessary (never {@code null})
|
||||||
* @return the resolved target return type, the standard return type, or {@code null}
|
* @return the resolved target return type or the standard method return type
|
||||||
* @since 3.2.5
|
* @since 3.2.5
|
||||||
*/
|
*/
|
||||||
public static Class<?> resolveReturnTypeForFactoryMethod(Method method, Object[] args, ClassLoader classLoader) {
|
public static Class<?> resolveReturnTypeForFactoryMethod(Method method, Object[] args, ClassLoader classLoader) {
|
||||||
|
|||||||
@@ -147,22 +147,23 @@ public class GenericTypeAwareAutowireCandidateResolver implements AutowireCandid
|
|||||||
protected ResolvableType getReturnTypeForFactoryMethod(RootBeanDefinition rbd, DependencyDescriptor descriptor) {
|
protected ResolvableType getReturnTypeForFactoryMethod(RootBeanDefinition rbd, DependencyDescriptor descriptor) {
|
||||||
// Should typically be set for any kind of factory method, since the BeanFactory
|
// Should typically be set for any kind of factory method, since the BeanFactory
|
||||||
// pre-resolves them before reaching out to the AutowireCandidateResolver...
|
// pre-resolves them before reaching out to the AutowireCandidateResolver...
|
||||||
Class<?> preResolved = rbd.resolvedFactoryMethodReturnType;
|
ResolvableType returnType = rbd.factoryMethodReturnType;
|
||||||
if (preResolved != null) {
|
if (returnType == null) {
|
||||||
return ResolvableType.forClass(preResolved);
|
Method factoryMethod = rbd.getResolvedFactoryMethod();
|
||||||
}
|
if (factoryMethod != null) {
|
||||||
else {
|
returnType = ResolvableType.forMethodReturnType(factoryMethod);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
|||||||
volatile Class<?> resolvedTargetType;
|
volatile Class<?> resolvedTargetType;
|
||||||
|
|
||||||
/** Package-visible field for caching the return type of a generically typed factory method */
|
/** 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 */
|
/** Common lock for the four constructor fields below */
|
||||||
final Object constructorArgumentLock = new Object();
|
final Object constructorArgumentLock = new Object();
|
||||||
|
|||||||
@@ -248,7 +248,13 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String[] getBeanNamesForType(ResolvableType type) {
|
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<String> matches = new ArrayList<>();
|
List<String> matches = new ArrayList<>();
|
||||||
for (Map.Entry<String, Object> entry : this.beans.entrySet()) {
|
for (Map.Entry<String, Object> entry : this.beans.entrySet()) {
|
||||||
String name = entry.getKey();
|
String name = entry.getKey();
|
||||||
|
|||||||
@@ -1295,7 +1295,6 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
|||||||
}
|
}
|
||||||
catch (UnsatisfiedDependencyException ex) {
|
catch (UnsatisfiedDependencyException ex) {
|
||||||
// expected
|
// expected
|
||||||
ex.printStackTrace();
|
|
||||||
assertSame(CustomAnnotationRequiredFieldResourceInjectionBean.class,
|
assertSame(CustomAnnotationRequiredFieldResourceInjectionBean.class,
|
||||||
ex.getInjectionPoint().getField().getDeclaringClass());
|
ex.getInjectionPoint().getField().getDeclaringClass());
|
||||||
}
|
}
|
||||||
@@ -1681,9 +1680,6 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
|||||||
assertSame(ir, bean.integerRepositoryMap.get("integerRepository"));
|
assertSame(ir, bean.integerRepositoryMap.get("integerRepository"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Qualifier("integerRepo")
|
|
||||||
private Repository<?> integerRepositoryQualifierProvider;
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGenericsBasedFieldInjectionWithSimpleMatch() {
|
public void testGenericsBasedFieldInjectionWithSimpleMatch() {
|
||||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||||
@@ -2194,6 +2190,10 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Qualifier("integerRepo")
|
||||||
|
private Repository<?> integerRepositoryQualifierProvider;
|
||||||
|
|
||||||
|
|
||||||
public static class ResourceInjectionBean {
|
public static class ResourceInjectionBean {
|
||||||
|
|
||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
|
|||||||
@@ -343,17 +343,15 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
|
|||||||
ResolvableType payloadType = null;
|
ResolvableType payloadType = null;
|
||||||
if (event instanceof PayloadApplicationEvent) {
|
if (event instanceof PayloadApplicationEvent) {
|
||||||
PayloadApplicationEvent<?> payloadEvent = (PayloadApplicationEvent<?>) event;
|
PayloadApplicationEvent<?> payloadEvent = (PayloadApplicationEvent<?>) event;
|
||||||
payloadType = payloadEvent.getResolvableType().as(
|
payloadType = payloadEvent.getResolvableType().as(PayloadApplicationEvent.class).getGeneric();
|
||||||
PayloadApplicationEvent.class).getGeneric(0);
|
|
||||||
}
|
}
|
||||||
for (ResolvableType declaredEventType : this.declaredEventTypes) {
|
for (ResolvableType declaredEventType : this.declaredEventTypes) {
|
||||||
if (!ApplicationEvent.class.isAssignableFrom(declaredEventType.getRawClass())
|
if (!ApplicationEvent.class.isAssignableFrom(declaredEventType.getRawClass()) && payloadType != null) {
|
||||||
&& payloadType != null) {
|
|
||||||
if (declaredEventType.isAssignableFrom(payloadType)) {
|
if (declaredEventType.isAssignableFrom(payloadType)) {
|
||||||
return declaredEventType;
|
return declaredEventType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (declaredEventType.getRawClass().isAssignableFrom(event.getClass())) {
|
if (declaredEventType.getRawClass().isInstance(event)) {
|
||||||
return declaredEventType;
|
return declaredEventType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2015 the original author or authors.
|
* Copyright 2002-2016 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -60,8 +60,8 @@ public class GenericApplicationListenerAdapter implements GenericApplicationList
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public boolean supportsEventType(ResolvableType eventType) {
|
public boolean supportsEventType(ResolvableType eventType) {
|
||||||
if (this.delegate instanceof SmartApplicationListener) {
|
if (this.delegate instanceof SmartApplicationListener) {
|
||||||
Class<? extends ApplicationEvent> eventClass = (Class<? extends ApplicationEvent>) eventType.getRawClass();
|
Class<? extends ApplicationEvent> eventClass = (Class<? extends ApplicationEvent>) eventType.resolve();
|
||||||
return ((SmartApplicationListener) this.delegate).supportsEventType(eventClass);
|
return (eventClass != null && ((SmartApplicationListener) this.delegate).supportsEventType(eventClass));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return (this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType));
|
return (this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType));
|
||||||
@@ -70,7 +70,7 @@ public class GenericApplicationListenerAdapter implements GenericApplicationList
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
|
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
|
||||||
return supportsEventType(ResolvableType.forType(eventType));
|
return supportsEventType(ResolvableType.forClass(eventType));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
|||||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.annotation.componentscan.simple.SimpleComponent;
|
import org.springframework.context.annotation.componentscan.simple.SimpleComponent;
|
||||||
|
import org.springframework.core.ResolvableType;
|
||||||
import org.springframework.core.annotation.Order;
|
import org.springframework.core.annotation.Order;
|
||||||
import org.springframework.core.env.StandardEnvironment;
|
import org.springframework.core.env.StandardEnvironment;
|
||||||
import org.springframework.core.io.DescriptiveResource;
|
import org.springframework.core.io.DescriptiveResource;
|
||||||
@@ -50,6 +51,7 @@ import org.springframework.stereotype.Component;
|
|||||||
import org.springframework.tests.sample.beans.ITestBean;
|
import org.springframework.tests.sample.beans.ITestBean;
|
||||||
import org.springframework.tests.sample.beans.TestBean;
|
import org.springframework.tests.sample.beans.TestBean;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
@@ -522,6 +524,33 @@ public class ConfigurationClassPostProcessorTests {
|
|||||||
assertSame(beanFactory.getBean("genericRepo"), beanFactory.getBean("repoConsumer"));
|
assertSame(beanFactory.getBean("genericRepo"), beanFactory.getBean("repoConsumer"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void genericsBasedInjectionWithLateGenericsMatching() {
|
||||||
|
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RepositoryConfiguration.class));
|
||||||
|
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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
|
@Test
|
||||||
public void testSelfReferenceExclusionForFactoryMethodOnSameBean() {
|
public void testSelfReferenceExclusionForFactoryMethodOnSameBean() {
|
||||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||||
|
|||||||
@@ -283,7 +283,7 @@ public class InvocableHandlerMethod extends HandlerMethod {
|
|||||||
return this.returnValue.getClass();
|
return this.returnValue.getClass();
|
||||||
}
|
}
|
||||||
if (!ResolvableType.NONE.equals(this.returnType)) {
|
if (!ResolvableType.NONE.equals(this.returnType)) {
|
||||||
return this.returnType.getRawClass();
|
return this.returnType.resolve();
|
||||||
}
|
}
|
||||||
return super.getParameterType();
|
return super.getParameterType();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -436,7 +436,7 @@ public class DefaultStompSession implements ConnectionHandlingStompSession {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Type type = handler.getPayloadType(stompHeaders);
|
Type type = handler.getPayloadType(stompHeaders);
|
||||||
Class<?> payloadType = ResolvableType.forType(type).getRawClass();
|
Class<?> payloadType = ResolvableType.forType(type).resolve();
|
||||||
Object object = getMessageConverter().fromMessage(message, payloadType);
|
Object object = getMessageConverter().fromMessage(message, payloadType);
|
||||||
if (object == null) {
|
if (object == null) {
|
||||||
throw new MessageConversionException("No suitable converter, payloadType=" + payloadType +
|
throw new MessageConversionException("No suitable converter, payloadType=" + payloadType +
|
||||||
|
|||||||
@@ -285,7 +285,7 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
|
|||||||
return this.returnValue.getClass();
|
return this.returnValue.getClass();
|
||||||
}
|
}
|
||||||
if (!ResolvableType.NONE.equals(this.returnType)) {
|
if (!ResolvableType.NONE.equals(this.returnType)) {
|
||||||
return this.returnType.getRawClass();
|
return this.returnType.resolve();
|
||||||
}
|
}
|
||||||
return super.getParameterType();
|
return super.getParameterType();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user