Skip to content

Commit 9412d78

Browse files
committed
Revised tests for generic FactoryBean type matching (backported)
See gh-32489
1 parent a0bd13c commit 9412d78

File tree

2 files changed

+89
-24
lines changed

2 files changed

+89
-24
lines changed

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

+69-13
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
import java.util.Set;
3030

3131
import org.junit.jupiter.api.Test;
32+
import org.junit.jupiter.params.ParameterizedTest;
33+
import org.junit.jupiter.params.provider.ValueSource;
3234
import org.mockito.Mockito;
3335

3436
import org.springframework.beans.factory.BeanCreationException;
@@ -756,25 +758,31 @@ void genericMatchingWithBeanNameDifferentiation() {
756758
assertThat(floatStoreNames).isEmpty();
757759
}
758760

759-
@Test
760-
void genericMatchingWithFullTypeDifferentiation() {
761+
@ParameterizedTest
762+
@ValueSource(classes = {NumberStoreFactory.class, NumberStoreFactoryBeans.class})
763+
void genericMatchingWithFullTypeDifferentiation(Class<?> factoryClass) {
761764
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
762765
bf.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
763766
bf.setAutowireCandidateResolver(new GenericTypeAwareAutowireCandidateResolver());
764767

765-
RootBeanDefinition bd1 = new RootBeanDefinition(NumberStoreFactory.class);
768+
RootBeanDefinition bd1 = new RootBeanDefinition(factoryClass);
766769
bd1.setFactoryMethodName("newDoubleStore");
767770
bf.registerBeanDefinition("store1", bd1);
768-
RootBeanDefinition bd2 = new RootBeanDefinition(NumberStoreFactory.class);
771+
RootBeanDefinition bd2 = new RootBeanDefinition(factoryClass);
769772
bd2.setFactoryMethodName("newFloatStore");
770773
bf.registerBeanDefinition("store2", bd2);
771-
bf.registerBeanDefinition("numberBean",
772-
new RootBeanDefinition(NumberBean.class, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR, false));
774+
RootBeanDefinition bd3 = new RootBeanDefinition(NumberBean.class);
775+
bd3.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
776+
bd3.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
777+
bf.registerBeanDefinition("numberBean", bd3);
773778

774-
NumberBean nb = bf.getBean(NumberBean.class);
775779
NumberStore<?> store1 = bf.getBean("store1", NumberStore.class);
776-
assertThat(nb.getDoubleStore()).isSameAs(store1);
777780
NumberStore<?> store2 = bf.getBean("store2", NumberStore.class);
781+
NumberBean nb = bf.getBean(NumberBean.class);
782+
assertThat(nb.getDoubleStore()).isSameAs(store1);
783+
assertThat(nb.getFloatStore()).isSameAs(store2);
784+
nb = bf.getBean(NumberBean.class);
785+
assertThat(nb.getDoubleStore()).isSameAs(store1);
778786
assertThat(nb.getFloatStore()).isSameAs(store2);
779787

780788
String[] numberStoreNames = bf.getBeanNamesForType(ResolvableType.forClass(NumberStore.class));
@@ -822,16 +830,17 @@ void genericMatchingWithFullTypeDifferentiation() {
822830
assertThat(floatStoreProvider.orderedStream()).singleElement().isEqualTo(store2);
823831
}
824832

825-
@Test
826-
void genericMatchingWithUnresolvedOrderedStream() {
833+
@ParameterizedTest
834+
@ValueSource(classes = {NumberStoreFactory.class, NumberStoreFactoryBeans.class})
835+
void genericMatchingWithUnresolvedOrderedStream(Class<?> factoryClass) {
827836
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
828837
bf.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
829838
bf.setAutowireCandidateResolver(new GenericTypeAwareAutowireCandidateResolver());
830839

831-
RootBeanDefinition bd1 = new RootBeanDefinition(NumberStoreFactory.class);
840+
RootBeanDefinition bd1 = new RootBeanDefinition(factoryClass);
832841
bd1.setFactoryMethodName("newDoubleStore");
833842
bf.registerBeanDefinition("store1", bd1);
834-
RootBeanDefinition bd2 = new RootBeanDefinition(NumberStoreFactory.class);
843+
RootBeanDefinition bd2 = new RootBeanDefinition(factoryClass);
835844
bd2.setFactoryMethodName("newFloatStore");
836845
bf.registerBeanDefinition("store2", bd2);
837846

@@ -854,7 +863,22 @@ void genericMatchingAgainstFactoryBeanClass() {
854863
bf.registerBeanDefinition("myFactoryBeanHolder",
855864
new RootBeanDefinition(MyFactoryBeanHolder.class, AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR, false));
856865

857-
assertThat(bf.getBean(MyFactoryBeanHolder.class).factoryBeans).contains(bf.getBean(MyFactoryBean.class));
866+
assertThat(bf.getBean(MyFactoryBeanHolder.class).factoryBeans).containsOnly(bf.getBean(MyFactoryBean.class));
867+
}
868+
869+
@Test // gh-32489
870+
void genericMatchingAgainstLazyFactoryBeanClass() {
871+
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
872+
bf.setAutowireCandidateResolver(new GenericTypeAwareAutowireCandidateResolver());
873+
874+
RootBeanDefinition bd = new RootBeanDefinition(MyFactoryBean.class);
875+
bd.setTargetType(ResolvableType.forClassWithGenerics(MyFactoryBean.class, String.class));
876+
bd.setLazyInit(true);
877+
bf.registerBeanDefinition("myFactoryBean", bd);
878+
bf.registerBeanDefinition("myFactoryBeanHolder",
879+
new RootBeanDefinition(MyFactoryBeanHolder.class, AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR, false));
880+
881+
assertThat(bf.getBean(MyFactoryBeanHolder.class).factoryBeans).containsOnly(bf.getBean(MyFactoryBean.class));
858882
}
859883

860884

@@ -974,6 +998,38 @@ public static NumberStore<Float> newFloatStore() {
974998
}
975999

9761000

1001+
public static class NumberStoreFactoryBeans {
1002+
1003+
@Order(1)
1004+
public static FactoryBean<NumberStore<Double>> newDoubleStore() {
1005+
return new FactoryBean<>() {
1006+
@Override
1007+
public NumberStore<Double> getObject() {
1008+
return new DoubleStore();
1009+
}
1010+
@Override
1011+
public Class<?> getObjectType() {
1012+
return DoubleStore.class;
1013+
}
1014+
};
1015+
}
1016+
1017+
@Order(0)
1018+
public static FactoryBean<NumberStore<Float>> newFloatStore() {
1019+
return new FactoryBean<>() {
1020+
@Override
1021+
public NumberStore<Float> getObject() {
1022+
return new FloatStore();
1023+
}
1024+
@Override
1025+
public Class<?> getObjectType() {
1026+
return FloatStore.class;
1027+
}
1028+
};
1029+
}
1030+
}
1031+
1032+
9771033
public interface MyGenericInterfaceForFactoryBeans<T> {
9781034
}
9791035

Diff for: spring-context/src/test/java/org/springframework/context/annotation/AnnotationConfigApplicationContextTests.java

+20-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 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.
@@ -307,8 +307,8 @@ void individualBeanWithNullReturningSupplier() {
307307
assertThat(ObjectUtils.containsElement(context.getBeanNamesForType(BeanC.class), "c")).isTrue();
308308

309309
assertThat(context.getBeansOfType(BeanA.class)).isEmpty();
310-
assertThat(context.getBeansOfType(BeanB.class).values().iterator().next()).isSameAs(context.getBean(BeanB.class));
311-
assertThat(context.getBeansOfType(BeanC.class).values().iterator().next()).isSameAs(context.getBean(BeanC.class));
310+
assertThat(context.getBeansOfType(BeanB.class).values()).singleElement().isSameAs(context.getBean(BeanB.class));
311+
assertThat(context.getBeansOfType(BeanC.class).values()).singleElement().isSameAs(context.getBean(BeanC.class));
312312

313313
assertThatExceptionOfType(NoSuchBeanDefinitionException.class)
314314
.isThrownBy(() -> context.getBeanFactory().resolveNamedBean(BeanA.class));
@@ -409,37 +409,43 @@ void individualBeanWithFactoryBeanTypeAsTargetType() {
409409
bd2.setTargetType(ResolvableType.forClassWithGenerics(FactoryBean.class, ResolvableType.forClassWithGenerics(GenericHolder.class, Integer.class)));
410410
bd2.setLazyInit(true);
411411
context.registerBeanDefinition("fb2", bd2);
412-
context.registerBeanDefinition("ip", new RootBeanDefinition(FactoryBeanInjectionPoints.class));
412+
RootBeanDefinition bd3 = new RootBeanDefinition(FactoryBeanInjectionPoints.class);
413+
bd3.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
414+
context.registerBeanDefinition("ip", bd3);
413415
context.refresh();
414416

417+
assertThat(context.getBean("ip", FactoryBeanInjectionPoints.class).factoryBean).isSameAs(context.getBean("&fb1"));
418+
assertThat(context.getBean("ip", FactoryBeanInjectionPoints.class).factoryResult).isSameAs(context.getBean("fb1"));
415419
assertThat(context.getType("&fb1")).isEqualTo(GenericHolderFactoryBean.class);
416420
assertThat(context.getType("fb1")).isEqualTo(GenericHolder.class);
417421
assertThat(context.getBeanNamesForType(FactoryBean.class)).hasSize(2);
418422
assertThat(context.getBeanNamesForType(GenericHolderFactoryBean.class)).hasSize(1);
419-
assertThat(context.getBean("ip", FactoryBeanInjectionPoints.class).factoryBean).isSameAs(context.getBean("&fb1"));
420-
assertThat(context.getBean("ip", FactoryBeanInjectionPoints.class).factoryResult).isSameAs(context.getBean("fb1"));
421423
}
422424

423425
@Test
424426
void individualBeanWithUnresolvedFactoryBeanTypeAsTargetType() {
425427
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
426428
RootBeanDefinition bd1 = new RootBeanDefinition();
427429
bd1.setBeanClass(GenericHolderFactoryBean.class);
428-
bd1.setTargetType(ResolvableType.forClassWithGenerics(FactoryBean.class, ResolvableType.forClassWithGenerics(GenericHolder.class, Object.class)));
430+
bd1.setTargetType(ResolvableType.forClassWithGenerics(FactoryBean.class, ResolvableType.forClassWithGenerics(GenericHolder.class, String.class)));
429431
bd1.setLazyInit(true);
430432
context.registerBeanDefinition("fb1", bd1);
431433
RootBeanDefinition bd2 = new RootBeanDefinition();
432434
bd2.setBeanClass(UntypedFactoryBean.class);
433435
bd2.setTargetType(ResolvableType.forClassWithGenerics(FactoryBean.class, ResolvableType.forClassWithGenerics(GenericHolder.class, Integer.class)));
434436
bd2.setLazyInit(true);
435437
context.registerBeanDefinition("fb2", bd2);
436-
context.registerBeanDefinition("ip", new RootBeanDefinition(FactoryResultInjectionPoint.class));
438+
RootBeanDefinition bd3 = new RootBeanDefinition(FactoryBeanInjectionPoints.class);
439+
bd3.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
440+
context.registerBeanDefinition("ip", bd3);
437441
context.refresh();
438442

443+
assertThat(context.getBean("ip", FactoryResultInjectionPoint.class).factoryResult).isSameAs(context.getBean("fb1"));
444+
assertThat(context.getBean("ip", FactoryResultInjectionPoint.class).factoryResult).isSameAs(context.getBean("fb1"));
439445
assertThat(context.getType("&fb1")).isEqualTo(GenericHolderFactoryBean.class);
440446
assertThat(context.getType("fb1")).isEqualTo(GenericHolder.class);
441447
assertThat(context.getBeanNamesForType(FactoryBean.class)).hasSize(2);
442-
assertThat(context.getBean("ip", FactoryResultInjectionPoint.class).factoryResult).isSameAs(context.getBean("fb1"));
448+
assertThat(context.getBeanNamesForType(FactoryBean.class)).hasSize(2);
443449
}
444450

445451
@Test
@@ -453,14 +459,17 @@ void individualBeanWithFactoryBeanObjectTypeAsTargetType() {
453459
bd2.setBeanClass(UntypedFactoryBean.class);
454460
bd2.setTargetType(ResolvableType.forClassWithGenerics(GenericHolder.class, Integer.class));
455461
context.registerBeanDefinition("fb2", bd2);
456-
context.registerBeanDefinition("ip", new RootBeanDefinition(FactoryResultInjectionPoint.class));
462+
RootBeanDefinition bd3 = new RootBeanDefinition(FactoryResultInjectionPoint.class);
463+
bd3.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
464+
context.registerBeanDefinition("ip", bd3);
457465
context.refresh();
458466

467+
assertThat(context.getBean("ip", FactoryResultInjectionPoint.class).factoryResult).isSameAs(context.getBean("fb1"));
468+
assertThat(context.getBean("ip", FactoryResultInjectionPoint.class).factoryResult).isSameAs(context.getBean("fb1"));
459469
assertThat(context.getType("&fb1")).isEqualTo(GenericHolderFactoryBean.class);
460470
assertThat(context.getType("fb1")).isEqualTo(GenericHolder.class);
461471
assertThat(context.getBeanNamesForType(FactoryBean.class)).hasSize(2);
462472
assertThat(context.getBeanNamesForType(GenericHolderFactoryBean.class)).hasSize(1);
463-
assertThat(context.getBean("ip", FactoryResultInjectionPoint.class).factoryResult).isSameAs(context.getBean("fb1"));
464473
}
465474

466475
@Test

0 commit comments

Comments
 (0)