Browse Source

Consistent getTypeForFactoryMethod result for parameterized method

Issue: SPR-16720

(cherry picked from commit 6184c4e)
pull/1876/head
Juergen Hoeller 8 years ago
parent
commit
c6a7732a30
  1. 16
      spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java
  2. 107
      spring-beans/src/test/java/org/springframework/beans/factory/support/BeanFactoryGenericsTests.java

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

@ -727,7 +727,8 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac @@ -727,7 +727,8 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
Class<?> returnType = AutowireUtils.resolveReturnTypeForFactoryMethod(
factoryMethod, args, getBeanClassLoader());
if (returnType != null) {
uniqueCandidate = (commonType == null ? factoryMethod : null);
uniqueCandidate = (commonType == null && returnType == factoryMethod.getReturnType() ?
factoryMethod : null);
commonType = ClassUtils.determineCommonAncestor(returnType, commonType);
if (commonType == null) {
// Ambiguous return types found: return null to indicate "not determinable".
@ -752,12 +753,15 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac @@ -752,12 +753,15 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
}
}
if (commonType != null) {
// Clear return type found: all factory methods return same type.
mbd.factoryMethodReturnType = (uniqueCandidate != null ?
ResolvableType.forMethodReturnType(uniqueCandidate) : ResolvableType.forClass(commonType));
if (commonType == null) {
return null;
}
return commonType;
// 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();
}
/**

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

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2018 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.
@ -40,6 +40,7 @@ import org.springframework.beans.factory.BeanCreationException; @@ -40,6 +40,7 @@ import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.beans.propertyeditors.CustomNumberEditor;
import org.springframework.core.OverridingClassLoader;
import org.springframework.core.ResolvableType;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.UrlResource;
@ -65,7 +66,7 @@ public class BeanFactoryGenericsTests { @@ -65,7 +66,7 @@ public class BeanFactoryGenericsTests {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
Set<String> input = new HashSet<String>();
Set<String> input = new HashSet<>();
input.add("4");
input.add("5");
rbd.getPropertyValues().add("integerSet", input);
@ -82,7 +83,7 @@ public class BeanFactoryGenericsTests { @@ -82,7 +83,7 @@ public class BeanFactoryGenericsTests {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
List<String> input = new ArrayList<String>();
List<String> input = new ArrayList<>();
input.add("http://localhost:8080");
input.add("http://localhost:9090");
rbd.getPropertyValues().add("resourceList", input);
@ -114,7 +115,7 @@ public class BeanFactoryGenericsTests { @@ -114,7 +115,7 @@ public class BeanFactoryGenericsTests {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
RootBeanDefinition rbd = new RootBeanDefinition(GenericIntegerBean.class);
List<Integer> input = new ArrayList<Integer>();
List<Integer> input = new ArrayList<>();
input.add(1);
rbd.getPropertyValues().add("testBeanList", input);
@ -146,7 +147,7 @@ public class BeanFactoryGenericsTests { @@ -146,7 +147,7 @@ public class BeanFactoryGenericsTests {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
Map<String, String> input = new HashMap<String, String>();
Map<String, String> input = new HashMap<>();
input.put("4", "5");
input.put("6", "7");
rbd.getPropertyValues().add("shortMap", input);
@ -178,7 +179,7 @@ public class BeanFactoryGenericsTests { @@ -178,7 +179,7 @@ public class BeanFactoryGenericsTests {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
Set<String> input = new HashSet<String>();
Set<String> input = new HashSet<>();
input.add("4");
input.add("5");
rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
@ -222,10 +223,10 @@ public class BeanFactoryGenericsTests { @@ -222,10 +223,10 @@ public class BeanFactoryGenericsTests {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
Set<String> input = new HashSet<String>();
Set<String> input = new HashSet<>();
input.add("4");
input.add("5");
List<String> input2 = new ArrayList<String>();
List<String> input2 = new ArrayList<>();
input2.add("http://localhost:8080");
input2.add("http://localhost:9090");
rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
@ -279,10 +280,10 @@ public class BeanFactoryGenericsTests { @@ -279,10 +280,10 @@ public class BeanFactoryGenericsTests {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
Set<String> input = new HashSet<String>();
Set<String> input = new HashSet<>();
input.add("4");
input.add("5");
Map<String, String> input2 = new HashMap<String, String>();
Map<String, String> input2 = new HashMap<>();
input2.put("4", "5");
input2.put("6", "7");
rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
@ -302,7 +303,7 @@ public class BeanFactoryGenericsTests { @@ -302,7 +303,7 @@ public class BeanFactoryGenericsTests {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
Map<String, String> input = new HashMap<String, String>();
Map<String, String> input = new HashMap<>();
input.put("4", "5");
input.put("6", "7");
rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
@ -321,10 +322,10 @@ public class BeanFactoryGenericsTests { @@ -321,10 +322,10 @@ public class BeanFactoryGenericsTests {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
Map<String, String> input = new HashMap<String, String>();
Map<String, String> input = new HashMap<>();
input.put("1", "0");
input.put("2", "3");
Map<String, String> input2 = new HashMap<String, String>();
Map<String, String> input2 = new HashMap<>();
input2.put("4", "5");
input2.put("6", "7");
rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
@ -347,7 +348,7 @@ public class BeanFactoryGenericsTests { @@ -347,7 +348,7 @@ public class BeanFactoryGenericsTests {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
Map<String, String> input = new HashMap<String, String>();
Map<String, String> input = new HashMap<>();
input.put("1", "0");
input.put("2", "3");
rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
@ -370,7 +371,7 @@ public class BeanFactoryGenericsTests { @@ -370,7 +371,7 @@ public class BeanFactoryGenericsTests {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
Map<Short, Integer> input = new HashMap<Short, Integer>();
Map<Short, Integer> input = new HashMap<>();
input.put(new Short((short) 1), new Integer(0));
input.put(new Short((short) 2), new Integer(3));
rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
@ -390,7 +391,7 @@ public class BeanFactoryGenericsTests { @@ -390,7 +391,7 @@ public class BeanFactoryGenericsTests {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
Map<String, String> input = new HashMap<String, String>();
Map<String, String> input = new HashMap<>();
input.put("4", "5");
input.put("6", "7");
rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
@ -413,11 +414,11 @@ public class BeanFactoryGenericsTests { @@ -413,11 +414,11 @@ public class BeanFactoryGenericsTests {
});
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
Map<String, AbstractCollection<?>> input = new HashMap<String, AbstractCollection<?>>();
HashSet<Integer> value1 = new HashSet<Integer>();
Map<String, AbstractCollection<?>> input = new HashMap<>();
HashSet<Integer> value1 = new HashSet<>();
value1.add(new Integer(1));
input.put("1", value1);
ArrayList<Boolean> value2 = new ArrayList<Boolean>();
ArrayList<Boolean> value2 = new ArrayList<>();
value2.add(Boolean.TRUE);
input.put("2", value2);
rbd.getConstructorArgumentValues().addGenericArgumentValue(Boolean.TRUE);
@ -437,7 +438,7 @@ public class BeanFactoryGenericsTests { @@ -437,7 +438,7 @@ public class BeanFactoryGenericsTests {
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
rbd.setFactoryMethodName("createInstance");
Set<String> input = new HashSet<String>();
Set<String> input = new HashSet<>();
input.add("4");
input.add("5");
rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
@ -455,10 +456,10 @@ public class BeanFactoryGenericsTests { @@ -455,10 +456,10 @@ public class BeanFactoryGenericsTests {
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
rbd.setFactoryMethodName("createInstance");
Set<String> input = new HashSet<String>();
Set<String> input = new HashSet<>();
input.add("4");
input.add("5");
List<String> input2 = new ArrayList<String>();
List<String> input2 = new ArrayList<>();
input2.add("http://localhost:8080");
input2.add("http://localhost:9090");
rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
@ -479,10 +480,10 @@ public class BeanFactoryGenericsTests { @@ -479,10 +480,10 @@ public class BeanFactoryGenericsTests {
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
rbd.setFactoryMethodName("createInstance");
Set<String> input = new HashSet<String>();
Set<String> input = new HashSet<>();
input.add("4");
input.add("5");
Map<String, String> input2 = new HashMap<String, String>();
Map<String, String> input2 = new HashMap<>();
input2.put("4", "5");
input2.put("6", "7");
rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
@ -503,7 +504,7 @@ public class BeanFactoryGenericsTests { @@ -503,7 +504,7 @@ public class BeanFactoryGenericsTests {
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
rbd.setFactoryMethodName("createInstance");
Map<String, String> input = new HashMap<String, String>();
Map<String, String> input = new HashMap<>();
input.put("4", "5");
input.put("6", "7");
rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
@ -523,10 +524,10 @@ public class BeanFactoryGenericsTests { @@ -523,10 +524,10 @@ public class BeanFactoryGenericsTests {
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
rbd.setFactoryMethodName("createInstance");
Map<String, String> input = new HashMap<String, String>();
Map<String, String> input = new HashMap<>();
input.put("1", "0");
input.put("2", "3");
Map<String, String> input2 = new HashMap<String, String>();
Map<String, String> input2 = new HashMap<>();
input2.put("4", "5");
input2.put("6", "7");
rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
@ -547,7 +548,7 @@ public class BeanFactoryGenericsTests { @@ -547,7 +548,7 @@ public class BeanFactoryGenericsTests {
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
rbd.setFactoryMethodName("createInstance");
Map<String, String> input = new HashMap<String, String>();
Map<String, String> input = new HashMap<>();
input.put("4", "5");
input.put("6", "7");
rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
@ -571,11 +572,11 @@ public class BeanFactoryGenericsTests { @@ -571,11 +572,11 @@ public class BeanFactoryGenericsTests {
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
rbd.setFactoryMethodName("createInstance");
Map<String, AbstractCollection<?>> input = new HashMap<String, AbstractCollection<?>>();
HashSet<Integer> value1 = new HashSet<Integer>();
Map<String, AbstractCollection<?>> input = new HashMap<>();
HashSet<Integer> value1 = new HashSet<>();
value1.add(new Integer(1));
input.put("1", value1);
ArrayList<Boolean> value2 = new ArrayList<Boolean>();
ArrayList<Boolean> value2 = new ArrayList<>();
value2.add(Boolean.TRUE);
input.put("2", value2);
rbd.getConstructorArgumentValues().addGenericArgumentValue(Boolean.TRUE);
@ -672,6 +673,8 @@ public class BeanFactoryGenericsTests { @@ -672,6 +673,8 @@ public class BeanFactoryGenericsTests {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.registerBeanDefinition("mock", rbd);
assertEquals(Runnable.class, bf.getType("mock"));
assertEquals(Runnable.class, bf.getType("mock"));
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
assertEquals(1, beans.size());
}
@ -700,6 +703,10 @@ public class BeanFactoryGenericsTests { @@ -700,6 +703,10 @@ public class BeanFactoryGenericsTests {
rbd.getConstructorArgumentValues().addGenericArgumentValue(Runnable.class);
bf.registerBeanDefinition("mock", rbd);
assertTrue(bf.isTypeMatch("mock", Runnable.class));
assertTrue(bf.isTypeMatch("mock", Runnable.class));
assertEquals(Runnable.class, bf.getType("mock"));
assertEquals(Runnable.class, bf.getType("mock"));
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
assertEquals(1, beans.size());
}
@ -717,6 +724,10 @@ public class BeanFactoryGenericsTests { @@ -717,6 +724,10 @@ public class BeanFactoryGenericsTests {
rbd.getConstructorArgumentValues().addGenericArgumentValue(Runnable.class.getName());
bf.registerBeanDefinition("mock", rbd);
assertTrue(bf.isTypeMatch("mock", Runnable.class));
assertTrue(bf.isTypeMatch("mock", Runnable.class));
assertEquals(Runnable.class, bf.getType("mock"));
assertEquals(Runnable.class, bf.getType("mock"));
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
assertEquals(1, beans.size());
}
@ -732,6 +743,10 @@ public class BeanFactoryGenericsTests { @@ -732,6 +743,10 @@ public class BeanFactoryGenericsTests {
rbd.getConstructorArgumentValues().addGenericArgumentValue(new TypedStringValue(Runnable.class.getName()));
bf.registerBeanDefinition("mock", rbd);
assertTrue(bf.isTypeMatch("mock", Runnable.class));
assertTrue(bf.isTypeMatch("mock", Runnable.class));
assertEquals(Runnable.class, bf.getType("mock"));
assertEquals(Runnable.class, bf.getType("mock"));
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
assertEquals(1, beans.size());
}
@ -749,6 +764,10 @@ public class BeanFactoryGenericsTests { @@ -749,6 +764,10 @@ public class BeanFactoryGenericsTests {
rbd.getConstructorArgumentValues().addGenericArgumentValue("x");
bf.registerBeanDefinition("mock", rbd);
assertFalse(bf.isTypeMatch("mock", Runnable.class));
assertFalse(bf.isTypeMatch("mock", Runnable.class));
assertNull(bf.getType("mock"));
assertNull(bf.getType("mock"));
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
assertEquals(0, beans.size());
}
@ -766,6 +785,32 @@ public class BeanFactoryGenericsTests { @@ -766,6 +785,32 @@ public class BeanFactoryGenericsTests {
rbd.getConstructorArgumentValues().addIndexedArgumentValue(0, Runnable.class);
bf.registerBeanDefinition("mock", rbd);
assertTrue(bf.isTypeMatch("mock", Runnable.class));
assertTrue(bf.isTypeMatch("mock", Runnable.class));
assertEquals(Runnable.class, bf.getType("mock"));
assertEquals(Runnable.class, bf.getType("mock"));
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
assertEquals(1, beans.size());
}
@Test // SPR-16720
public void parameterizedInstanceFactoryMethodWithTempClassLoader() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.setTempClassLoader(new OverridingClassLoader(getClass().getClassLoader()));
RootBeanDefinition rbd = new RootBeanDefinition(MocksControl.class);
bf.registerBeanDefinition("mocksControl", rbd);
rbd = new RootBeanDefinition();
rbd.setFactoryBeanName("mocksControl");
rbd.setFactoryMethodName("createMock");
rbd.getConstructorArgumentValues().addGenericArgumentValue(Runnable.class);
bf.registerBeanDefinition("mock", rbd);
assertTrue(bf.isTypeMatch("mock", Runnable.class));
assertTrue(bf.isTypeMatch("mock", Runnable.class));
assertEquals(Runnable.class, bf.getType("mock"));
assertEquals(Runnable.class, bf.getType("mock"));
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
assertEquals(1, beans.size());
}

Loading…
Cancel
Save