Add missing variants of getBeanNamesForType
Update `ListableBeanFactory` and `BeanFactoryUtils` to add the missing
`getBeanNamesForType` methods that accept a `ResolvableType` rather
than a `Class`.
This completes the work started in 778a01943b
.
Closes gh-23335
This commit is contained in:
parent
30132b42c6
commit
2ee1ce61c0
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 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.
|
||||
|
@ -172,6 +172,44 @@ public abstract class BeanFactoryUtils {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all bean names for the given type, including those defined in ancestor
|
||||
* factories. Will return unique names in case of overridden bean definitions.
|
||||
* <p>Does consider objects created by FactoryBeans if the "allowEagerInit"
|
||||
* flag is set, which means that FactoryBeans will get initialized. If the
|
||||
* object created by the FactoryBean doesn't match, the raw FactoryBean itself
|
||||
* will be matched against the type. If "allowEagerInit" is not set,
|
||||
* only raw FactoryBeans will be checked (which doesn't require initialization
|
||||
* of each FactoryBean).
|
||||
* @param lbf the bean factory
|
||||
* @param includeNonSingletons whether to include prototype or scoped beans too
|
||||
* or just singletons (also applies to FactoryBeans)
|
||||
* @param allowEagerInit whether to initialize <i>lazy-init singletons</i> and
|
||||
* <i>objects created by FactoryBeans</i> (or by factory methods with a
|
||||
* "factory-bean" reference) for the type check. Note that FactoryBeans need to be
|
||||
* eagerly initialized to determine their type: So be aware that passing in "true"
|
||||
* for this flag will initialize FactoryBeans and "factory-bean" references.
|
||||
* @param type the type that beans must match (as a {@code ResolvableType})
|
||||
* @return the array of matching bean names, or an empty array if none
|
||||
* @since 5.2
|
||||
* @see ListableBeanFactory#getBeanNamesForType(ResolvableType, boolean, boolean)
|
||||
*/
|
||||
public static String[] beanNamesForTypeIncludingAncestors(
|
||||
ListableBeanFactory lbf, ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
|
||||
|
||||
Assert.notNull(lbf, "ListableBeanFactory must not be null");
|
||||
String[] result = lbf.getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
|
||||
if (lbf instanceof HierarchicalBeanFactory) {
|
||||
HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf;
|
||||
if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) {
|
||||
String[] parentResult = beanNamesForTypeIncludingAncestors(
|
||||
(ListableBeanFactory) hbf.getParentBeanFactory(), type, includeNonSingletons, allowEagerInit);
|
||||
result = mergeNamesWithParent(result, parentResult, hbf);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all bean names for the given type, including those defined in ancestor
|
||||
* factories. Will return unique names in case of overridden bean definitions.
|
||||
|
|
|
@ -116,6 +116,40 @@ public interface ListableBeanFactory extends BeanFactory {
|
|||
*/
|
||||
String[] getBeanNamesForType(ResolvableType type);
|
||||
|
||||
/**
|
||||
* Return the names of beans matching the given type (including subclasses),
|
||||
* judging from either bean definitions or the value of {@code getObjectType}
|
||||
* in the case of FactoryBeans.
|
||||
* <p><b>NOTE: This method introspects top-level beans only.</b> It does <i>not</i>
|
||||
* check nested beans which might match the specified type as well.
|
||||
* <p>Does consider objects created by FactoryBeans if the "allowEagerInit" flag is set,
|
||||
* which means that FactoryBeans will get initialized. If the object created by the
|
||||
* FactoryBean doesn't match, the raw FactoryBean itself will be matched against the
|
||||
* type. If "allowEagerInit" is not set, only raw FactoryBeans will be checked
|
||||
* (which doesn't require initialization of each FactoryBean).
|
||||
* <p>Does not consider any hierarchy this factory may participate in.
|
||||
* Use BeanFactoryUtils' {@code beanNamesForTypeIncludingAncestors}
|
||||
* to include beans in ancestor factories too.
|
||||
* <p>Note: Does <i>not</i> ignore singleton beans that have been registered
|
||||
* by other means than bean definitions.
|
||||
* <p>Bean names returned by this method should always return bean names <i>in the
|
||||
* order of definition</i> in the backend configuration, as far as possible.
|
||||
* @param type the generically typed class or interface to match
|
||||
* @param includeNonSingletons whether to include prototype or scoped beans too
|
||||
* or just singletons (also applies to FactoryBeans)
|
||||
* @param allowEagerInit whether to initialize <i>lazy-init singletons</i> and
|
||||
* <i>objects created by FactoryBeans</i> (or by factory methods with a
|
||||
* "factory-bean" reference) for the type check. Note that FactoryBeans need to be
|
||||
* eagerly initialized to determine their type: So be aware that passing in "true"
|
||||
* for this flag will initialize FactoryBeans and "factory-bean" references.
|
||||
* @return the names of beans (or objects created by FactoryBeans) matching
|
||||
* the given object type (including subclasses), or an empty array if none
|
||||
* @since 5.2
|
||||
* @see FactoryBean#getObjectType
|
||||
* @see BeanFactoryUtils#beanNamesForTypeIncludingAncestors(ListableBeanFactory, ResolvableType, boolean, boolean)
|
||||
*/
|
||||
String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit);
|
||||
|
||||
/**
|
||||
* Return the names of beans matching the given type (including subclasses),
|
||||
* judging from either bean definitions or the value of {@code getObjectType}
|
||||
|
|
|
@ -463,12 +463,17 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||
|
||||
@Override
|
||||
public String[] getBeanNamesForType(ResolvableType type) {
|
||||
return getBeanNamesForType(type, true, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
|
||||
Class<?> resolved = type.resolve();
|
||||
if (resolved != null && !type.hasGenerics()) {
|
||||
return getBeanNamesForType(resolved, true, true);
|
||||
return getBeanNamesForType(resolved, includeNonSingletons, includeNonSingletons);
|
||||
}
|
||||
else {
|
||||
return doGetBeanNamesForType(type, true, true);
|
||||
return doGetBeanNamesForType(type, includeNonSingletons, includeNonSingletons);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 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.
|
||||
|
@ -329,26 +329,32 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
|
|||
|
||||
@Override
|
||||
public String[] getBeanNamesForType(@Nullable ResolvableType type) {
|
||||
boolean isFactoryType = false;
|
||||
if (type != null) {
|
||||
Class<?> resolved = type.resolve();
|
||||
if (resolved != null && FactoryBean.class.isAssignableFrom(resolved)) {
|
||||
isFactoryType = true;
|
||||
}
|
||||
}
|
||||
return getBeanNamesForType(type, true, true);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String[] getBeanNamesForType(@Nullable ResolvableType type,
|
||||
boolean includeNonSingletons, boolean allowEagerInit) {
|
||||
|
||||
Class<?> resolved = (type != null ? type.resolve() : null);
|
||||
boolean isFactoryType = resolved != null && FactoryBean.class.isAssignableFrom(resolved);
|
||||
List<String> matches = new ArrayList<>();
|
||||
|
||||
for (Map.Entry<String, Object> entry : this.beans.entrySet()) {
|
||||
String name = entry.getKey();
|
||||
String beanName = entry.getKey();
|
||||
Object beanInstance = entry.getValue();
|
||||
if (beanInstance instanceof FactoryBean && !isFactoryType) {
|
||||
Class<?> objectType = ((FactoryBean<?>) beanInstance).getObjectType();
|
||||
if (objectType != null && (type == null || type.isAssignableFrom(objectType))) {
|
||||
matches.add(name);
|
||||
FactoryBean<?> factoryBean = (FactoryBean<?>) beanInstance;
|
||||
Class<?> objectType = factoryBean.getObjectType();
|
||||
if ((includeNonSingletons || factoryBean.isSingleton()) &&
|
||||
objectType != null && (type == null || type.isAssignableFrom(objectType))) {
|
||||
matches.add(beanName);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (type == null || type.isInstance(beanInstance)) {
|
||||
matches.add(name);
|
||||
matches.add(beanName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -362,7 +368,7 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
|
|||
|
||||
@Override
|
||||
public String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
|
||||
return getBeanNamesForType(ResolvableType.forClass(type));
|
||||
return getBeanNamesForType(ResolvableType.forClass(type), includeNonSingletons, allowEagerInit);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1751,6 +1751,8 @@ public class DefaultListableBeanFactoryTests {
|
|||
assertThat(lbf.getBeanNamesForType(ConstructorDependencyFactoryBean.class).length).isEqualTo(1);
|
||||
assertThat(lbf.getBeanNamesForType(ResolvableType.forClassWithGenerics(FactoryBean.class, Object.class)).length).isEqualTo(1);
|
||||
assertThat(lbf.getBeanNamesForType(ResolvableType.forClassWithGenerics(FactoryBean.class, String.class)).length).isEqualTo(0);
|
||||
assertThat(lbf.getBeanNamesForType(ResolvableType.forClassWithGenerics(FactoryBean.class, Object.class), true, true).length).isEqualTo(1);
|
||||
assertThat(lbf.getBeanNamesForType(ResolvableType.forClassWithGenerics(FactoryBean.class, String.class), true, true).length).isEqualTo(0);
|
||||
}
|
||||
|
||||
private RootBeanDefinition createConstructorDependencyBeanDefinition(int age) {
|
||||
|
|
|
@ -1208,6 +1208,12 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
|||
return getBeanFactory().getBeanNamesForType(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
|
||||
assertBeanFactoryActive();
|
||||
return getBeanFactory().getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getBeanNamesForType(@Nullable Class<?> type) {
|
||||
assertBeanFactoryActive();
|
||||
|
|
|
@ -251,6 +251,11 @@ class StubWebApplicationContext implements WebApplicationContext {
|
|||
return this.beanFactory.getBeanNamesForType(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getBeanNamesForType(@Nullable ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
|
||||
return this.beanFactory.getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getBeanNamesForType(@Nullable Class<?> type) {
|
||||
return this.beanFactory.getBeanNamesForType(type);
|
||||
|
|
Loading…
Reference in New Issue