Skip to content

Commit 4763154

Browse files
committed
Consistent getTypeForFactoryMethod result for parameterized method
Issue: SPR-16720 (cherry picked from commit 6184c4e)
1 parent 8f7e5e7 commit 4763154

File tree

2 files changed

+56
-7
lines changed

2 files changed

+56
-7
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -752,7 +752,8 @@ protected Class<?> getTypeForFactoryMethod(String beanName, RootBeanDefinition m
752752
}
753753
Class<?> returnType = AutowireUtils.resolveReturnTypeForFactoryMethod(
754754
factoryMethod, args, getBeanClassLoader());
755-
uniqueCandidate = (commonType == null ? factoryMethod : null);
755+
uniqueCandidate = (commonType == null && returnType == factoryMethod.getReturnType() ?
756+
factoryMethod : null);
756757
commonType = ClassUtils.determineCommonAncestor(returnType, commonType);
757758
if (commonType == null) {
758759
// Ambiguous return types found: return null to indicate "not determinable".
@@ -776,12 +777,15 @@ protected Class<?> getTypeForFactoryMethod(String beanName, RootBeanDefinition m
776777
}
777778
}
778779

779-
if (commonType != null) {
780-
// Clear return type found: all factory methods return same type.
781-
mbd.factoryMethodReturnType = (uniqueCandidate != null ?
782-
ResolvableType.forMethodReturnType(uniqueCandidate) : ResolvableType.forClass(commonType));
780+
if (commonType == null) {
781+
return null;
783782
}
784-
return commonType;
783+
// Common return type found: all factory methods return same type. For a non-parameterized
784+
// unique candidate, cache the full type declaration context of the target factory method.
785+
cachedReturnType = (uniqueCandidate != null ?
786+
ResolvableType.forMethodReturnType(uniqueCandidate) : ResolvableType.forClass(commonType));
787+
mbd.factoryMethodReturnType = cachedReturnType;
788+
return cachedReturnType.resolve();
785789
}
786790

787791
/**

spring-beans/src/test/java/org/springframework/beans/factory/support/BeanFactoryGenericsTests.java

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -40,6 +40,7 @@
4040
import org.springframework.beans.factory.config.TypedStringValue;
4141
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
4242
import org.springframework.beans.propertyeditors.CustomNumberEditor;
43+
import org.springframework.core.OverridingClassLoader;
4344
import org.springframework.core.ResolvableType;
4445
import org.springframework.core.io.ClassPathResource;
4546
import org.springframework.core.io.UrlResource;
@@ -672,6 +673,8 @@ public void parameterizedStaticFactoryMethod() {
672673
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
673674
bf.registerBeanDefinition("mock", rbd);
674675

676+
assertEquals(Runnable.class, bf.getType("mock"));
677+
assertEquals(Runnable.class, bf.getType("mock"));
675678
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
676679
assertEquals(1, beans.size());
677680
}
@@ -700,6 +703,10 @@ public void parameterizedInstanceFactoryMethod() {
700703
rbd.getConstructorArgumentValues().addGenericArgumentValue(Runnable.class);
701704
bf.registerBeanDefinition("mock", rbd);
702705

706+
assertTrue(bf.isTypeMatch("mock", Runnable.class));
707+
assertTrue(bf.isTypeMatch("mock", Runnable.class));
708+
assertEquals(Runnable.class, bf.getType("mock"));
709+
assertEquals(Runnable.class, bf.getType("mock"));
703710
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
704711
assertEquals(1, beans.size());
705712
}
@@ -717,6 +724,10 @@ public void parameterizedInstanceFactoryMethodWithNonResolvedClassName() {
717724
rbd.getConstructorArgumentValues().addGenericArgumentValue(Runnable.class.getName());
718725
bf.registerBeanDefinition("mock", rbd);
719726

727+
assertTrue(bf.isTypeMatch("mock", Runnable.class));
728+
assertTrue(bf.isTypeMatch("mock", Runnable.class));
729+
assertEquals(Runnable.class, bf.getType("mock"));
730+
assertEquals(Runnable.class, bf.getType("mock"));
720731
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
721732
assertEquals(1, beans.size());
722733
}
@@ -732,6 +743,10 @@ public void parameterizedInstanceFactoryMethodWithWrappedClassName() {
732743
rbd.getConstructorArgumentValues().addGenericArgumentValue(new TypedStringValue(Runnable.class.getName()));
733744
bf.registerBeanDefinition("mock", rbd);
734745

746+
assertTrue(bf.isTypeMatch("mock", Runnable.class));
747+
assertTrue(bf.isTypeMatch("mock", Runnable.class));
748+
assertEquals(Runnable.class, bf.getType("mock"));
749+
assertEquals(Runnable.class, bf.getType("mock"));
735750
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
736751
assertEquals(1, beans.size());
737752
}
@@ -749,6 +764,10 @@ public void parameterizedInstanceFactoryMethodWithInvalidClassName() {
749764
rbd.getConstructorArgumentValues().addGenericArgumentValue("x");
750765
bf.registerBeanDefinition("mock", rbd);
751766

767+
assertFalse(bf.isTypeMatch("mock", Runnable.class));
768+
assertFalse(bf.isTypeMatch("mock", Runnable.class));
769+
assertNull(bf.getType("mock"));
770+
assertNull(bf.getType("mock"));
752771
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
753772
assertEquals(0, beans.size());
754773
}
@@ -766,6 +785,32 @@ public void parameterizedInstanceFactoryMethodWithIndexedArgument() {
766785
rbd.getConstructorArgumentValues().addIndexedArgumentValue(0, Runnable.class);
767786
bf.registerBeanDefinition("mock", rbd);
768787

788+
assertTrue(bf.isTypeMatch("mock", Runnable.class));
789+
assertTrue(bf.isTypeMatch("mock", Runnable.class));
790+
assertEquals(Runnable.class, bf.getType("mock"));
791+
assertEquals(Runnable.class, bf.getType("mock"));
792+
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
793+
assertEquals(1, beans.size());
794+
}
795+
796+
@Test // SPR-16720
797+
public void parameterizedInstanceFactoryMethodWithTempClassLoader() {
798+
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
799+
bf.setTempClassLoader(new OverridingClassLoader(getClass().getClassLoader()));
800+
801+
RootBeanDefinition rbd = new RootBeanDefinition(MocksControl.class);
802+
bf.registerBeanDefinition("mocksControl", rbd);
803+
804+
rbd = new RootBeanDefinition();
805+
rbd.setFactoryBeanName("mocksControl");
806+
rbd.setFactoryMethodName("createMock");
807+
rbd.getConstructorArgumentValues().addGenericArgumentValue(Runnable.class);
808+
bf.registerBeanDefinition("mock", rbd);
809+
810+
assertTrue(bf.isTypeMatch("mock", Runnable.class));
811+
assertTrue(bf.isTypeMatch("mock", Runnable.class));
812+
assertEquals(Runnable.class, bf.getType("mock"));
813+
assertEquals(Runnable.class, bf.getType("mock"));
769814
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
770815
assertEquals(1, beans.size());
771816
}

0 commit comments

Comments
 (0)