Consistent type-based bean lookup for internal resolution paths
Includes additional tests for List/ObjectProvider dependencies. See gh-35101
This commit is contained in:
parent
2e9e45ee55
commit
06ef82e9a5
|
@ -496,7 +496,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||||
@Override
|
@Override
|
||||||
public Stream<T> stream() {
|
public Stream<T> stream() {
|
||||||
return Arrays.stream(beanNamesForStream(requiredType, true, allowEagerInit))
|
return Arrays.stream(beanNamesForStream(requiredType, true, allowEagerInit))
|
||||||
.map(name -> (T) getBean(name))
|
.map(name -> (T) resolveBean(name, requiredType))
|
||||||
.filter(bean -> !(bean instanceof NullBean));
|
.filter(bean -> !(bean instanceof NullBean));
|
||||||
}
|
}
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@ -508,7 +508,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||||
}
|
}
|
||||||
Map<String, T> matchingBeans = CollectionUtils.newLinkedHashMap(beanNames.length);
|
Map<String, T> matchingBeans = CollectionUtils.newLinkedHashMap(beanNames.length);
|
||||||
for (String beanName : beanNames) {
|
for (String beanName : beanNames) {
|
||||||
Object beanInstance = getBean(beanName);
|
Object beanInstance = resolveBean(beanName, requiredType);
|
||||||
if (!(beanInstance instanceof NullBean)) {
|
if (!(beanInstance instanceof NullBean)) {
|
||||||
matchingBeans.put(beanName, (T) beanInstance);
|
matchingBeans.put(beanName, (T) beanInstance);
|
||||||
}
|
}
|
||||||
|
@ -521,7 +521,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||||
public Stream<T> stream(Predicate<Class<?>> customFilter, boolean includeNonSingletons) {
|
public Stream<T> stream(Predicate<Class<?>> customFilter, boolean includeNonSingletons) {
|
||||||
return Arrays.stream(beanNamesForStream(requiredType, includeNonSingletons, allowEagerInit))
|
return Arrays.stream(beanNamesForStream(requiredType, includeNonSingletons, allowEagerInit))
|
||||||
.filter(name -> customFilter.test(getType(name)))
|
.filter(name -> customFilter.test(getType(name)))
|
||||||
.map(name -> (T) getBean(name))
|
.map(name -> (T) resolveBean(name, requiredType))
|
||||||
.filter(bean -> !(bean instanceof NullBean));
|
.filter(bean -> !(bean instanceof NullBean));
|
||||||
}
|
}
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@ -534,7 +534,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||||
Map<String, T> matchingBeans = CollectionUtils.newLinkedHashMap(beanNames.length);
|
Map<String, T> matchingBeans = CollectionUtils.newLinkedHashMap(beanNames.length);
|
||||||
for (String beanName : beanNames) {
|
for (String beanName : beanNames) {
|
||||||
if (customFilter.test(getType(beanName))) {
|
if (customFilter.test(getType(beanName))) {
|
||||||
Object beanInstance = getBean(beanName);
|
Object beanInstance = resolveBean(beanName, requiredType);
|
||||||
if (!(beanInstance instanceof NullBean)) {
|
if (!(beanInstance instanceof NullBean)) {
|
||||||
matchingBeans.put(beanName, (T) beanInstance);
|
matchingBeans.put(beanName, (T) beanInstance);
|
||||||
}
|
}
|
||||||
|
@ -1207,6 +1207,17 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Object resolveBean(String beanName, ResolvableType requiredType) {
|
||||||
|
try {
|
||||||
|
// Need to provide required type for SmartFactoryBean
|
||||||
|
return getBean(beanName, requiredType.toClass());
|
||||||
|
}
|
||||||
|
catch (BeanNotOfRequiredTypeException ex) {
|
||||||
|
// Probably a null bean...
|
||||||
|
return getBean(beanName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static String getThreadNamePrefix() {
|
private static String getThreadNamePrefix() {
|
||||||
String name = Thread.currentThread().getName();
|
String name = Thread.currentThread().getName();
|
||||||
int numberSeparator = name.lastIndexOf('-');
|
int numberSeparator = name.lastIndexOf('-');
|
||||||
|
@ -1542,7 +1553,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||||
Map<String, Object> candidates = CollectionUtils.newLinkedHashMap(candidateNames.length);
|
Map<String, Object> candidates = CollectionUtils.newLinkedHashMap(candidateNames.length);
|
||||||
for (String beanName : candidateNames) {
|
for (String beanName : candidateNames) {
|
||||||
if (containsSingleton(beanName) && args == null) {
|
if (containsSingleton(beanName) && args == null) {
|
||||||
Object beanInstance = getBean(beanName);
|
Object beanInstance = resolveBean(beanName, requiredType);
|
||||||
candidates.put(beanName, (beanInstance instanceof NullBean ? null : beanInstance));
|
candidates.put(beanName, (beanInstance instanceof NullBean ? null : beanInstance));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -1659,7 +1670,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||||
if (autowiredBeanNames != null) {
|
if (autowiredBeanNames != null) {
|
||||||
autowiredBeanNames.add(dependencyName);
|
autowiredBeanNames.add(dependencyName);
|
||||||
}
|
}
|
||||||
Object dependencyBean = getBean(dependencyName);
|
Object dependencyBean = resolveBean(dependencyName, descriptor.getResolvableType());
|
||||||
return resolveInstance(dependencyBean, descriptor, type, dependencyName);
|
return resolveInstance(dependencyBean, descriptor, type, dependencyName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2582,16 +2593,18 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<Object> stream(Predicate<Class<?>> customFilter, boolean includeNonSingletons) {
|
public Stream<Object> stream(Predicate<Class<?>> customFilter, boolean includeNonSingletons) {
|
||||||
return Arrays.stream(beanNamesForStream(this.descriptor.getResolvableType(), includeNonSingletons, true))
|
ResolvableType type = this.descriptor.getResolvableType();
|
||||||
|
return Arrays.stream(beanNamesForStream(type, includeNonSingletons, true))
|
||||||
.filter(name -> AutowireUtils.isAutowireCandidate(DefaultListableBeanFactory.this, name))
|
.filter(name -> AutowireUtils.isAutowireCandidate(DefaultListableBeanFactory.this, name))
|
||||||
.filter(name -> customFilter.test(getType(name)))
|
.filter(name -> customFilter.test(getType(name)))
|
||||||
.map(name -> getBean(name))
|
.map(name -> resolveBean(name, type))
|
||||||
.filter(bean -> !(bean instanceof NullBean));
|
.filter(bean -> !(bean instanceof NullBean));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<Object> orderedStream(Predicate<Class<?>> customFilter, boolean includeNonSingletons) {
|
public Stream<Object> orderedStream(Predicate<Class<?>> customFilter, boolean includeNonSingletons) {
|
||||||
String[] beanNames = beanNamesForStream(this.descriptor.getResolvableType(), includeNonSingletons, true);
|
ResolvableType type = this.descriptor.getResolvableType();
|
||||||
|
String[] beanNames = beanNamesForStream(type, includeNonSingletons, true);
|
||||||
if (beanNames.length == 0) {
|
if (beanNames.length == 0) {
|
||||||
return Stream.empty();
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
@ -2599,7 +2612,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||||
for (String beanName : beanNames) {
|
for (String beanName : beanNames) {
|
||||||
if (AutowireUtils.isAutowireCandidate(DefaultListableBeanFactory.this, beanName) &&
|
if (AutowireUtils.isAutowireCandidate(DefaultListableBeanFactory.this, beanName) &&
|
||||||
customFilter.test(getType(beanName))) {
|
customFilter.test(getType(beanName))) {
|
||||||
Object beanInstance = getBean(beanName);
|
Object beanInstance = resolveBean(beanName, type);
|
||||||
if (!(beanInstance instanceof NullBean)) {
|
if (!(beanInstance instanceof NullBean)) {
|
||||||
matchingBeans.put(beanName, beanInstance);
|
matchingBeans.put(beanName, beanInstance);
|
||||||
}
|
}
|
||||||
|
|
|
@ -307,7 +307,7 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
|
||||||
public T getObject() throws BeansException {
|
public T getObject() throws BeansException {
|
||||||
String[] beanNames = getBeanNamesForType(requiredType);
|
String[] beanNames = getBeanNamesForType(requiredType);
|
||||||
if (beanNames.length == 1) {
|
if (beanNames.length == 1) {
|
||||||
return (T) getBean(beanNames[0], requiredType);
|
return (T) getBean(beanNames[0], requiredType.toClass());
|
||||||
}
|
}
|
||||||
else if (beanNames.length > 1) {
|
else if (beanNames.length > 1) {
|
||||||
throw new NoUniqueBeanDefinitionException(requiredType, beanNames);
|
throw new NoUniqueBeanDefinitionException(requiredType, beanNames);
|
||||||
|
@ -333,7 +333,7 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
|
||||||
public @Nullable T getIfAvailable() throws BeansException {
|
public @Nullable T getIfAvailable() throws BeansException {
|
||||||
String[] beanNames = getBeanNamesForType(requiredType);
|
String[] beanNames = getBeanNamesForType(requiredType);
|
||||||
if (beanNames.length == 1) {
|
if (beanNames.length == 1) {
|
||||||
return (T) getBean(beanNames[0]);
|
return (T) getBean(beanNames[0], requiredType.toClass());
|
||||||
}
|
}
|
||||||
else if (beanNames.length > 1) {
|
else if (beanNames.length > 1) {
|
||||||
throw new NoUniqueBeanDefinitionException(requiredType, beanNames);
|
throw new NoUniqueBeanDefinitionException(requiredType, beanNames);
|
||||||
|
@ -346,7 +346,7 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
|
||||||
public @Nullable T getIfUnique() throws BeansException {
|
public @Nullable T getIfUnique() throws BeansException {
|
||||||
String[] beanNames = getBeanNamesForType(requiredType);
|
String[] beanNames = getBeanNamesForType(requiredType);
|
||||||
if (beanNames.length == 1) {
|
if (beanNames.length == 1) {
|
||||||
return (T) getBean(beanNames[0]);
|
return (T) getBean(beanNames[0], requiredType.toClass());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return null;
|
return null;
|
||||||
|
@ -354,7 +354,8 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public Stream<T> stream() {
|
public Stream<T> stream() {
|
||||||
return Arrays.stream(getBeanNamesForType(requiredType)).map(name -> (T) getBean(name));
|
return Arrays.stream(getBeanNamesForType(requiredType))
|
||||||
|
.map(name -> (T) getBean(name, requiredType.toClass()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -464,8 +464,40 @@ class BeanFactoryUtilsTests {
|
||||||
lbf.registerSingleton("fb2", fb2);
|
lbf.registerSingleton("fb2", fb2);
|
||||||
lbf.registerSingleton("sfb1", sfb1);
|
lbf.registerSingleton("sfb1", sfb1);
|
||||||
lbf.registerSingleton("sfb2", sfb2);
|
lbf.registerSingleton("sfb2", sfb2);
|
||||||
|
lbf.registerBeanDefinition("recipient",
|
||||||
|
new RootBeanDefinition(Recipient.class, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR, false));
|
||||||
|
|
||||||
testSupportsMultipleTypesWithStaticFactory(lbf);
|
Recipient recipient = lbf.getBean("recipient", Recipient.class);
|
||||||
|
assertThat(recipient.sfb1).isSameAs(lbf.getBean("sfb1", TestBean.class));
|
||||||
|
assertThat(recipient.sfb2).isSameAs(lbf.getBean("sfb2", TestBean.class));
|
||||||
|
|
||||||
|
List<ITestBean> testBeanList = recipient.testBeanList;
|
||||||
|
assertThat(testBeanList).hasSize(5);
|
||||||
|
assertThat(testBeanList.get(0)).isSameAs(bean);
|
||||||
|
assertThat(testBeanList.get(1)).isSameAs(fb1.getObject());
|
||||||
|
assertThat(testBeanList.get(2)).isInstanceOf(TestBean.class);
|
||||||
|
assertThat(testBeanList.get(3)).isSameAs(lbf.getBean("sfb1", TestBean.class));
|
||||||
|
assertThat(testBeanList.get(4)).isSameAs(lbf.getBean("sfb2", TestBean.class));
|
||||||
|
|
||||||
|
List<CharSequence> stringList = recipient.stringList;
|
||||||
|
assertThat(stringList).hasSize(2);
|
||||||
|
assertThat(stringList.get(0)).isSameAs(lbf.getBean("sfb1", String.class));
|
||||||
|
assertThat(stringList.get(1)).isSameAs(lbf.getBean("sfb2", String.class));
|
||||||
|
|
||||||
|
testBeanList = recipient.testBeanProvider.stream().toList();
|
||||||
|
assertThat(testBeanList).hasSize(5);
|
||||||
|
assertThat(testBeanList.get(0)).isSameAs(bean);
|
||||||
|
assertThat(testBeanList.get(1)).isSameAs(fb1.getObject());
|
||||||
|
assertThat(testBeanList.get(2)).isInstanceOf(TestBean.class);
|
||||||
|
assertThat(testBeanList.get(3)).isSameAs(lbf.getBean("sfb1", TestBean.class));
|
||||||
|
assertThat(testBeanList.get(4)).isSameAs(lbf.getBean("sfb2", TestBean.class));
|
||||||
|
|
||||||
|
stringList = recipient.stringProvider.stream().toList();
|
||||||
|
assertThat(stringList).hasSize(2);
|
||||||
|
assertThat(stringList.get(0)).isSameAs(lbf.getBean("sfb1", String.class));
|
||||||
|
assertThat(stringList.get(1)).isSameAs(lbf.getBean("sfb2", String.class));
|
||||||
|
|
||||||
|
testSupportsMultipleTypes(lbf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -483,22 +515,35 @@ class BeanFactoryUtilsTests {
|
||||||
lbf.addBean("sfb1", sfb1);
|
lbf.addBean("sfb1", sfb1);
|
||||||
lbf.addBean("sfb2", sfb2);
|
lbf.addBean("sfb2", sfb2);
|
||||||
|
|
||||||
testSupportsMultipleTypesWithStaticFactory(lbf);
|
testSupportsMultipleTypes(lbf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void testSupportsMultipleTypesWithStaticFactory(ListableBeanFactory lbf) {
|
void testSupportsMultipleTypes(ListableBeanFactory lbf) {
|
||||||
|
List<ITestBean> testBeanList = lbf.getBeanProvider(ITestBean.class).stream().toList();
|
||||||
|
assertThat(testBeanList).hasSize(5);
|
||||||
|
assertThat(testBeanList.get(0)).isSameAs(lbf.getBean("bean", TestBean.class));
|
||||||
|
assertThat(testBeanList.get(1)).isSameAs(lbf.getBean("fb1", TestBean.class));
|
||||||
|
assertThat(testBeanList.get(2)).isInstanceOf(TestBean.class);
|
||||||
|
assertThat(testBeanList.get(3)).isSameAs(lbf.getBean("sfb1", TestBean.class));
|
||||||
|
assertThat(testBeanList.get(4)).isSameAs(lbf.getBean("sfb2", TestBean.class));
|
||||||
|
|
||||||
|
List<CharSequence> stringList = lbf.getBeanProvider(CharSequence.class).stream().toList();
|
||||||
|
assertThat(stringList).hasSize(2);
|
||||||
|
assertThat(stringList.get(0)).isSameAs(lbf.getBean("sfb1", String.class));
|
||||||
|
assertThat(stringList.get(1)).isSameAs(lbf.getBean("sfb2", String.class));
|
||||||
|
|
||||||
Map<String, ?> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, ITestBean.class);
|
Map<String, ?> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, ITestBean.class);
|
||||||
assertThat(beans).hasSize(5);
|
assertThat(beans).hasSize(5);
|
||||||
assertThat(beans.get("bean")).isSameAs(lbf.getBean("bean"));
|
assertThat(beans.get("bean")).isSameAs(lbf.getBean("bean"));
|
||||||
assertThat(beans.get("fb1")).isSameAs(lbf.getBean("&fb1", DummyFactory.class).getObject());
|
assertThat(beans.get("fb1")).isSameAs(lbf.getBean("fb1",TestBean.class));
|
||||||
assertThat(beans.get("fb2")).isInstanceOf(TestBean.class);
|
assertThat(beans.get("fb2")).isInstanceOf(TestBean.class);
|
||||||
assertThat(beans.get("sfb1")).isInstanceOf(TestBean.class);
|
assertThat(beans.get("sfb1")).isSameAs(lbf.getBean("sfb1", TestBean.class));
|
||||||
assertThat(beans.get("sfb2")).isInstanceOf(TestBean.class);
|
assertThat(beans.get("sfb2")).isSameAs(lbf.getBean("sfb2", TestBean.class));
|
||||||
|
|
||||||
beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, CharSequence.class);
|
beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, CharSequence.class);
|
||||||
assertThat(beans).hasSize(2);
|
assertThat(beans).hasSize(2);
|
||||||
assertThat(beans.get("sfb1")).isInstanceOf(String.class);
|
assertThat(beans.get("sfb1")).isSameAs(lbf.getBean("sfb1", String.class));
|
||||||
assertThat(beans.get("sfb2")).isInstanceOf(String.class);
|
assertThat(beans.get("sfb2")).isSameAs(lbf.getBean("sfb1", String.class));
|
||||||
|
|
||||||
assertThat(lbf.getBean("sfb1", ITestBean.class)).isInstanceOf(TestBean.class);
|
assertThat(lbf.getBean("sfb1", ITestBean.class)).isInstanceOf(TestBean.class);
|
||||||
assertThat(lbf.getBean("sfb2", ITestBean.class)).isInstanceOf(TestBean.class);
|
assertThat(lbf.getBean("sfb2", ITestBean.class)).isInstanceOf(TestBean.class);
|
||||||
|
@ -604,4 +649,30 @@ class BeanFactoryUtilsTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static class Recipient {
|
||||||
|
|
||||||
|
public Recipient(ITestBean sfb1, ITestBean sfb2, List<ITestBean> testBeanList, List<CharSequence> stringList,
|
||||||
|
ObjectProvider<ITestBean> testBeanProvider, ObjectProvider<CharSequence> stringProvider) {
|
||||||
|
this.sfb1 = sfb1;
|
||||||
|
this.sfb2 = sfb2;
|
||||||
|
this.testBeanList = testBeanList;
|
||||||
|
this.stringList = stringList;
|
||||||
|
this.testBeanProvider = testBeanProvider;
|
||||||
|
this.stringProvider = stringProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
ITestBean sfb1;
|
||||||
|
|
||||||
|
ITestBean sfb2;
|
||||||
|
|
||||||
|
List<ITestBean> testBeanList;
|
||||||
|
|
||||||
|
List<CharSequence> stringList;
|
||||||
|
|
||||||
|
ObjectProvider<ITestBean> testBeanProvider;
|
||||||
|
|
||||||
|
ObjectProvider<CharSequence> stringProvider;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue