Browse Source

Revised tests for generic FactoryBean type matching (backported)

See gh-32489
pull/33048/head
Juergen Hoeller 2 years ago
parent
commit
9412d782ce
  1. 82
      spring-beans/src/test/java/org/springframework/beans/factory/support/BeanFactoryGenericsTests.java
  2. 31
      spring-context/src/test/java/org/springframework/context/annotation/AnnotationConfigApplicationContextTests.java

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

@ -29,6 +29,8 @@ import java.util.Map; @@ -29,6 +29,8 @@ import java.util.Map;
import java.util.Set;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.Mockito;
import org.springframework.beans.factory.BeanCreationException;
@ -756,25 +758,31 @@ class BeanFactoryGenericsTests { @@ -756,25 +758,31 @@ class BeanFactoryGenericsTests {
assertThat(floatStoreNames).isEmpty();
}
@Test
void genericMatchingWithFullTypeDifferentiation() {
@ParameterizedTest
@ValueSource(classes = {NumberStoreFactory.class, NumberStoreFactoryBeans.class})
void genericMatchingWithFullTypeDifferentiation(Class<?> factoryClass) {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
bf.setAutowireCandidateResolver(new GenericTypeAwareAutowireCandidateResolver());
RootBeanDefinition bd1 = new RootBeanDefinition(NumberStoreFactory.class);
RootBeanDefinition bd1 = new RootBeanDefinition(factoryClass);
bd1.setFactoryMethodName("newDoubleStore");
bf.registerBeanDefinition("store1", bd1);
RootBeanDefinition bd2 = new RootBeanDefinition(NumberStoreFactory.class);
RootBeanDefinition bd2 = new RootBeanDefinition(factoryClass);
bd2.setFactoryMethodName("newFloatStore");
bf.registerBeanDefinition("store2", bd2);
bf.registerBeanDefinition("numberBean",
new RootBeanDefinition(NumberBean.class, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR, false));
RootBeanDefinition bd3 = new RootBeanDefinition(NumberBean.class);
bd3.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
bd3.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
bf.registerBeanDefinition("numberBean", bd3);
NumberBean nb = bf.getBean(NumberBean.class);
NumberStore<?> store1 = bf.getBean("store1", NumberStore.class);
assertThat(nb.getDoubleStore()).isSameAs(store1);
NumberStore<?> store2 = bf.getBean("store2", NumberStore.class);
NumberBean nb = bf.getBean(NumberBean.class);
assertThat(nb.getDoubleStore()).isSameAs(store1);
assertThat(nb.getFloatStore()).isSameAs(store2);
nb = bf.getBean(NumberBean.class);
assertThat(nb.getDoubleStore()).isSameAs(store1);
assertThat(nb.getFloatStore()).isSameAs(store2);
String[] numberStoreNames = bf.getBeanNamesForType(ResolvableType.forClass(NumberStore.class));
@ -822,16 +830,17 @@ class BeanFactoryGenericsTests { @@ -822,16 +830,17 @@ class BeanFactoryGenericsTests {
assertThat(floatStoreProvider.orderedStream()).singleElement().isEqualTo(store2);
}
@Test
void genericMatchingWithUnresolvedOrderedStream() {
@ParameterizedTest
@ValueSource(classes = {NumberStoreFactory.class, NumberStoreFactoryBeans.class})
void genericMatchingWithUnresolvedOrderedStream(Class<?> factoryClass) {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
bf.setAutowireCandidateResolver(new GenericTypeAwareAutowireCandidateResolver());
RootBeanDefinition bd1 = new RootBeanDefinition(NumberStoreFactory.class);
RootBeanDefinition bd1 = new RootBeanDefinition(factoryClass);
bd1.setFactoryMethodName("newDoubleStore");
bf.registerBeanDefinition("store1", bd1);
RootBeanDefinition bd2 = new RootBeanDefinition(NumberStoreFactory.class);
RootBeanDefinition bd2 = new RootBeanDefinition(factoryClass);
bd2.setFactoryMethodName("newFloatStore");
bf.registerBeanDefinition("store2", bd2);
@ -854,7 +863,22 @@ class BeanFactoryGenericsTests { @@ -854,7 +863,22 @@ class BeanFactoryGenericsTests {
bf.registerBeanDefinition("myFactoryBeanHolder",
new RootBeanDefinition(MyFactoryBeanHolder.class, AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR, false));
assertThat(bf.getBean(MyFactoryBeanHolder.class).factoryBeans).contains(bf.getBean(MyFactoryBean.class));
assertThat(bf.getBean(MyFactoryBeanHolder.class).factoryBeans).containsOnly(bf.getBean(MyFactoryBean.class));
}
@Test // gh-32489
void genericMatchingAgainstLazyFactoryBeanClass() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.setAutowireCandidateResolver(new GenericTypeAwareAutowireCandidateResolver());
RootBeanDefinition bd = new RootBeanDefinition(MyFactoryBean.class);
bd.setTargetType(ResolvableType.forClassWithGenerics(MyFactoryBean.class, String.class));
bd.setLazyInit(true);
bf.registerBeanDefinition("myFactoryBean", bd);
bf.registerBeanDefinition("myFactoryBeanHolder",
new RootBeanDefinition(MyFactoryBeanHolder.class, AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR, false));
assertThat(bf.getBean(MyFactoryBeanHolder.class).factoryBeans).containsOnly(bf.getBean(MyFactoryBean.class));
}
@ -974,6 +998,38 @@ class BeanFactoryGenericsTests { @@ -974,6 +998,38 @@ class BeanFactoryGenericsTests {
}
public static class NumberStoreFactoryBeans {
@Order(1)
public static FactoryBean<NumberStore<Double>> newDoubleStore() {
return new FactoryBean<>() {
@Override
public NumberStore<Double> getObject() {
return new DoubleStore();
}
@Override
public Class<?> getObjectType() {
return DoubleStore.class;
}
};
}
@Order(0)
public static FactoryBean<NumberStore<Float>> newFloatStore() {
return new FactoryBean<>() {
@Override
public NumberStore<Float> getObject() {
return new FloatStore();
}
@Override
public Class<?> getObjectType() {
return FloatStore.class;
}
};
}
}
public interface MyGenericInterfaceForFactoryBeans<T> {
}

31
spring-context/src/test/java/org/springframework/context/annotation/AnnotationConfigApplicationContextTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 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.
@ -307,8 +307,8 @@ class AnnotationConfigApplicationContextTests { @@ -307,8 +307,8 @@ class AnnotationConfigApplicationContextTests {
assertThat(ObjectUtils.containsElement(context.getBeanNamesForType(BeanC.class), "c")).isTrue();
assertThat(context.getBeansOfType(BeanA.class)).isEmpty();
assertThat(context.getBeansOfType(BeanB.class).values().iterator().next()).isSameAs(context.getBean(BeanB.class));
assertThat(context.getBeansOfType(BeanC.class).values().iterator().next()).isSameAs(context.getBean(BeanC.class));
assertThat(context.getBeansOfType(BeanB.class).values()).singleElement().isSameAs(context.getBean(BeanB.class));
assertThat(context.getBeansOfType(BeanC.class).values()).singleElement().isSameAs(context.getBean(BeanC.class));
assertThatExceptionOfType(NoSuchBeanDefinitionException.class)
.isThrownBy(() -> context.getBeanFactory().resolveNamedBean(BeanA.class));
@ -409,15 +409,17 @@ class AnnotationConfigApplicationContextTests { @@ -409,15 +409,17 @@ class AnnotationConfigApplicationContextTests {
bd2.setTargetType(ResolvableType.forClassWithGenerics(FactoryBean.class, ResolvableType.forClassWithGenerics(GenericHolder.class, Integer.class)));
bd2.setLazyInit(true);
context.registerBeanDefinition("fb2", bd2);
context.registerBeanDefinition("ip", new RootBeanDefinition(FactoryBeanInjectionPoints.class));
RootBeanDefinition bd3 = new RootBeanDefinition(FactoryBeanInjectionPoints.class);
bd3.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
context.registerBeanDefinition("ip", bd3);
context.refresh();
assertThat(context.getBean("ip", FactoryBeanInjectionPoints.class).factoryBean).isSameAs(context.getBean("&fb1"));
assertThat(context.getBean("ip", FactoryBeanInjectionPoints.class).factoryResult).isSameAs(context.getBean("fb1"));
assertThat(context.getType("&fb1")).isEqualTo(GenericHolderFactoryBean.class);
assertThat(context.getType("fb1")).isEqualTo(GenericHolder.class);
assertThat(context.getBeanNamesForType(FactoryBean.class)).hasSize(2);
assertThat(context.getBeanNamesForType(GenericHolderFactoryBean.class)).hasSize(1);
assertThat(context.getBean("ip", FactoryBeanInjectionPoints.class).factoryBean).isSameAs(context.getBean("&fb1"));
assertThat(context.getBean("ip", FactoryBeanInjectionPoints.class).factoryResult).isSameAs(context.getBean("fb1"));
}
@Test
@ -425,7 +427,7 @@ class AnnotationConfigApplicationContextTests { @@ -425,7 +427,7 @@ class AnnotationConfigApplicationContextTests {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
RootBeanDefinition bd1 = new RootBeanDefinition();
bd1.setBeanClass(GenericHolderFactoryBean.class);
bd1.setTargetType(ResolvableType.forClassWithGenerics(FactoryBean.class, ResolvableType.forClassWithGenerics(GenericHolder.class, Object.class)));
bd1.setTargetType(ResolvableType.forClassWithGenerics(FactoryBean.class, ResolvableType.forClassWithGenerics(GenericHolder.class, String.class)));
bd1.setLazyInit(true);
context.registerBeanDefinition("fb1", bd1);
RootBeanDefinition bd2 = new RootBeanDefinition();
@ -433,13 +435,17 @@ class AnnotationConfigApplicationContextTests { @@ -433,13 +435,17 @@ class AnnotationConfigApplicationContextTests {
bd2.setTargetType(ResolvableType.forClassWithGenerics(FactoryBean.class, ResolvableType.forClassWithGenerics(GenericHolder.class, Integer.class)));
bd2.setLazyInit(true);
context.registerBeanDefinition("fb2", bd2);
context.registerBeanDefinition("ip", new RootBeanDefinition(FactoryResultInjectionPoint.class));
RootBeanDefinition bd3 = new RootBeanDefinition(FactoryBeanInjectionPoints.class);
bd3.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
context.registerBeanDefinition("ip", bd3);
context.refresh();
assertThat(context.getBean("ip", FactoryResultInjectionPoint.class).factoryResult).isSameAs(context.getBean("fb1"));
assertThat(context.getBean("ip", FactoryResultInjectionPoint.class).factoryResult).isSameAs(context.getBean("fb1"));
assertThat(context.getType("&fb1")).isEqualTo(GenericHolderFactoryBean.class);
assertThat(context.getType("fb1")).isEqualTo(GenericHolder.class);
assertThat(context.getBeanNamesForType(FactoryBean.class)).hasSize(2);
assertThat(context.getBean("ip", FactoryResultInjectionPoint.class).factoryResult).isSameAs(context.getBean("fb1"));
assertThat(context.getBeanNamesForType(FactoryBean.class)).hasSize(2);
}
@Test
@ -453,14 +459,17 @@ class AnnotationConfigApplicationContextTests { @@ -453,14 +459,17 @@ class AnnotationConfigApplicationContextTests {
bd2.setBeanClass(UntypedFactoryBean.class);
bd2.setTargetType(ResolvableType.forClassWithGenerics(GenericHolder.class, Integer.class));
context.registerBeanDefinition("fb2", bd2);
context.registerBeanDefinition("ip", new RootBeanDefinition(FactoryResultInjectionPoint.class));
RootBeanDefinition bd3 = new RootBeanDefinition(FactoryResultInjectionPoint.class);
bd3.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
context.registerBeanDefinition("ip", bd3);
context.refresh();
assertThat(context.getBean("ip", FactoryResultInjectionPoint.class).factoryResult).isSameAs(context.getBean("fb1"));
assertThat(context.getBean("ip", FactoryResultInjectionPoint.class).factoryResult).isSameAs(context.getBean("fb1"));
assertThat(context.getType("&fb1")).isEqualTo(GenericHolderFactoryBean.class);
assertThat(context.getType("fb1")).isEqualTo(GenericHolder.class);
assertThat(context.getBeanNamesForType(FactoryBean.class)).hasSize(2);
assertThat(context.getBeanNamesForType(GenericHolderFactoryBean.class)).hasSize(1);
assertThat(context.getBean("ip", FactoryResultInjectionPoint.class).factoryResult).isSameAs(context.getBean("fb1"));
}
@Test

Loading…
Cancel
Save