Skip to content

Commit c6a7732

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

File tree

2 files changed

+86
-37
lines changed

2 files changed

+86
-37
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
@@ -727,7 +727,8 @@ protected Class<?> getTypeForFactoryMethod(String beanName, RootBeanDefinition m
727727
Class<?> returnType = AutowireUtils.resolveReturnTypeForFactoryMethod(
728728
factoryMethod, args, getBeanClassLoader());
729729
if (returnType != null) {
730-
uniqueCandidate = (commonType == null ? factoryMethod : null);
730+
uniqueCandidate = (commonType == null && returnType == factoryMethod.getReturnType() ?
731+
factoryMethod : null);
731732
commonType = ClassUtils.determineCommonAncestor(returnType, commonType);
732733
if (commonType == null) {
733734
// Ambiguous return types found: return null to indicate "not determinable".
@@ -752,12 +753,15 @@ protected Class<?> getTypeForFactoryMethod(String beanName, RootBeanDefinition m
752753
}
753754
}
754755

755-
if (commonType != null) {
756-
// Clear return type found: all factory methods return same type.
757-
mbd.factoryMethodReturnType = (uniqueCandidate != null ?
758-
ResolvableType.forMethodReturnType(uniqueCandidate) : ResolvableType.forClass(commonType));
756+
if (commonType == null) {
757+
return null;
759758
}
760-
return commonType;
759+
// Common return type found: all factory methods return same type. For a non-parameterized
760+
// unique candidate, cache the full type declaration context of the target factory method.
761+
cachedReturnType = (uniqueCandidate != null ?
762+
ResolvableType.forMethodReturnType(uniqueCandidate) : ResolvableType.forClass(commonType));
763+
mbd.factoryMethodReturnType = cachedReturnType;
764+
return cachedReturnType.resolve();
761765
}
762766

763767
/**

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

Lines changed: 76 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 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;
@@ -65,7 +66,7 @@ public void testGenericSetProperty() {
6566
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
6667
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
6768

68-
Set<String> input = new HashSet<String>();
69+
Set<String> input = new HashSet<>();
6970
input.add("4");
7071
input.add("5");
7172
rbd.getPropertyValues().add("integerSet", input);
@@ -82,7 +83,7 @@ public void testGenericListProperty() throws MalformedURLException {
8283
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
8384
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
8485

85-
List<String> input = new ArrayList<String>();
86+
List<String> input = new ArrayList<>();
8687
input.add("http://localhost:8080");
8788
input.add("http://localhost:9090");
8889
rbd.getPropertyValues().add("resourceList", input);
@@ -114,7 +115,7 @@ public void testGenericListPropertyWithInvalidElementType() {
114115
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
115116
RootBeanDefinition rbd = new RootBeanDefinition(GenericIntegerBean.class);
116117

117-
List<Integer> input = new ArrayList<Integer>();
118+
List<Integer> input = new ArrayList<>();
118119
input.add(1);
119120
rbd.getPropertyValues().add("testBeanList", input);
120121

@@ -146,7 +147,7 @@ public void testGenericMapProperty() {
146147
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
147148
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
148149

149-
Map<String, String> input = new HashMap<String, String>();
150+
Map<String, String> input = new HashMap<>();
150151
input.put("4", "5");
151152
input.put("6", "7");
152153
rbd.getPropertyValues().add("shortMap", input);
@@ -178,7 +179,7 @@ public void testGenericSetConstructor() {
178179
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
179180
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
180181

181-
Set<String> input = new HashSet<String>();
182+
Set<String> input = new HashSet<>();
182183
input.add("4");
183184
input.add("5");
184185
rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
@@ -222,10 +223,10 @@ public void testGenericSetListConstructor() throws MalformedURLException {
222223
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
223224
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
224225

225-
Set<String> input = new HashSet<String>();
226+
Set<String> input = new HashSet<>();
226227
input.add("4");
227228
input.add("5");
228-
List<String> input2 = new ArrayList<String>();
229+
List<String> input2 = new ArrayList<>();
229230
input2.add("http://localhost:8080");
230231
input2.add("http://localhost:9090");
231232
rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
@@ -279,10 +280,10 @@ public void testGenericSetMapConstructor() throws MalformedURLException {
279280
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
280281
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
281282

282-
Set<String> input = new HashSet<String>();
283+
Set<String> input = new HashSet<>();
283284
input.add("4");
284285
input.add("5");
285-
Map<String, String> input2 = new HashMap<String, String>();
286+
Map<String, String> input2 = new HashMap<>();
286287
input2.put("4", "5");
287288
input2.put("6", "7");
288289
rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
@@ -302,7 +303,7 @@ public void testGenericMapResourceConstructor() throws MalformedURLException {
302303
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
303304
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
304305

305-
Map<String, String> input = new HashMap<String, String>();
306+
Map<String, String> input = new HashMap<>();
306307
input.put("4", "5");
307308
input.put("6", "7");
308309
rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
@@ -321,10 +322,10 @@ public void testGenericMapMapConstructor() throws MalformedURLException {
321322
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
322323
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
323324

324-
Map<String, String> input = new HashMap<String, String>();
325+
Map<String, String> input = new HashMap<>();
325326
input.put("1", "0");
326327
input.put("2", "3");
327-
Map<String, String> input2 = new HashMap<String, String>();
328+
Map<String, String> input2 = new HashMap<>();
328329
input2.put("4", "5");
329330
input2.put("6", "7");
330331
rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
@@ -347,7 +348,7 @@ public void testGenericMapMapConstructorWithSameRefAndConversion() throws Malfor
347348
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
348349
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
349350

350-
Map<String, String> input = new HashMap<String, String>();
351+
Map<String, String> input = new HashMap<>();
351352
input.put("1", "0");
352353
input.put("2", "3");
353354
rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
@@ -370,7 +371,7 @@ public void testGenericMapMapConstructorWithSameRefAndNoConversion() throws Malf
370371
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
371372
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
372373

373-
Map<Short, Integer> input = new HashMap<Short, Integer>();
374+
Map<Short, Integer> input = new HashMap<>();
374375
input.put(new Short((short) 1), new Integer(0));
375376
input.put(new Short((short) 2), new Integer(3));
376377
rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
@@ -390,7 +391,7 @@ public void testGenericMapWithKeyTypeConstructor() throws MalformedURLException
390391
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
391392
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
392393

393-
Map<String, String> input = new HashMap<String, String>();
394+
Map<String, String> input = new HashMap<>();
394395
input.put("4", "5");
395396
input.put("6", "7");
396397
rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
@@ -413,11 +414,11 @@ public void registerCustomEditors(PropertyEditorRegistry registry) {
413414
});
414415
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
415416

416-
Map<String, AbstractCollection<?>> input = new HashMap<String, AbstractCollection<?>>();
417-
HashSet<Integer> value1 = new HashSet<Integer>();
417+
Map<String, AbstractCollection<?>> input = new HashMap<>();
418+
HashSet<Integer> value1 = new HashSet<>();
418419
value1.add(new Integer(1));
419420
input.put("1", value1);
420-
ArrayList<Boolean> value2 = new ArrayList<Boolean>();
421+
ArrayList<Boolean> value2 = new ArrayList<>();
421422
value2.add(Boolean.TRUE);
422423
input.put("2", value2);
423424
rbd.getConstructorArgumentValues().addGenericArgumentValue(Boolean.TRUE);
@@ -437,7 +438,7 @@ public void testGenericSetFactoryMethod() {
437438
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
438439
rbd.setFactoryMethodName("createInstance");
439440

440-
Set<String> input = new HashSet<String>();
441+
Set<String> input = new HashSet<>();
441442
input.add("4");
442443
input.add("5");
443444
rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
@@ -455,10 +456,10 @@ public void testGenericSetListFactoryMethod() throws MalformedURLException {
455456
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
456457
rbd.setFactoryMethodName("createInstance");
457458

458-
Set<String> input = new HashSet<String>();
459+
Set<String> input = new HashSet<>();
459460
input.add("4");
460461
input.add("5");
461-
List<String> input2 = new ArrayList<String>();
462+
List<String> input2 = new ArrayList<>();
462463
input2.add("http://localhost:8080");
463464
input2.add("http://localhost:9090");
464465
rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
@@ -479,10 +480,10 @@ public void testGenericSetMapFactoryMethod() throws MalformedURLException {
479480
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
480481
rbd.setFactoryMethodName("createInstance");
481482

482-
Set<String> input = new HashSet<String>();
483+
Set<String> input = new HashSet<>();
483484
input.add("4");
484485
input.add("5");
485-
Map<String, String> input2 = new HashMap<String, String>();
486+
Map<String, String> input2 = new HashMap<>();
486487
input2.put("4", "5");
487488
input2.put("6", "7");
488489
rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
@@ -503,7 +504,7 @@ public void testGenericMapResourceFactoryMethod() throws MalformedURLException {
503504
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
504505
rbd.setFactoryMethodName("createInstance");
505506

506-
Map<String, String> input = new HashMap<String, String>();
507+
Map<String, String> input = new HashMap<>();
507508
input.put("4", "5");
508509
input.put("6", "7");
509510
rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
@@ -523,10 +524,10 @@ public void testGenericMapMapFactoryMethod() throws MalformedURLException {
523524
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
524525
rbd.setFactoryMethodName("createInstance");
525526

526-
Map<String, String> input = new HashMap<String, String>();
527+
Map<String, String> input = new HashMap<>();
527528
input.put("1", "0");
528529
input.put("2", "3");
529-
Map<String, String> input2 = new HashMap<String, String>();
530+
Map<String, String> input2 = new HashMap<>();
530531
input2.put("4", "5");
531532
input2.put("6", "7");
532533
rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
@@ -547,7 +548,7 @@ public void testGenericMapWithKeyTypeFactoryMethod() throws MalformedURLExceptio
547548
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
548549
rbd.setFactoryMethodName("createInstance");
549550

550-
Map<String, String> input = new HashMap<String, String>();
551+
Map<String, String> input = new HashMap<>();
551552
input.put("4", "5");
552553
input.put("6", "7");
553554
rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
@@ -571,11 +572,11 @@ public void registerCustomEditors(PropertyEditorRegistry registry) {
571572
RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
572573
rbd.setFactoryMethodName("createInstance");
573574

574-
Map<String, AbstractCollection<?>> input = new HashMap<String, AbstractCollection<?>>();
575-
HashSet<Integer> value1 = new HashSet<Integer>();
575+
Map<String, AbstractCollection<?>> input = new HashMap<>();
576+
HashSet<Integer> value1 = new HashSet<>();
576577
value1.add(new Integer(1));
577578
input.put("1", value1);
578-
ArrayList<Boolean> value2 = new ArrayList<Boolean>();
579+
ArrayList<Boolean> value2 = new ArrayList<>();
579580
value2.add(Boolean.TRUE);
580581
input.put("2", value2);
581582
rbd.getConstructorArgumentValues().addGenericArgumentValue(Boolean.TRUE);
@@ -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)