Skip to content

Commit 2ee1ce6

Browse files
philwebbjhoeller
authored andcommitted
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 778a019. Closes gh-23335
1 parent 30132b4 commit 2ee1ce6

File tree

7 files changed

+113
-17
lines changed

7 files changed

+113
-17
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/BeanFactoryUtils.java

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 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.
@@ -172,6 +172,44 @@ public static String[] beanNamesForTypeIncludingAncestors(ListableBeanFactory lb
172172
return result;
173173
}
174174

175+
/**
176+
* Get all bean names for the given type, including those defined in ancestor
177+
* factories. Will return unique names in case of overridden bean definitions.
178+
* <p>Does consider objects created by FactoryBeans if the "allowEagerInit"
179+
* flag is set, which means that FactoryBeans will get initialized. If the
180+
* object created by the FactoryBean doesn't match, the raw FactoryBean itself
181+
* will be matched against the type. If "allowEagerInit" is not set,
182+
* only raw FactoryBeans will be checked (which doesn't require initialization
183+
* of each FactoryBean).
184+
* @param lbf the bean factory
185+
* @param includeNonSingletons whether to include prototype or scoped beans too
186+
* or just singletons (also applies to FactoryBeans)
187+
* @param allowEagerInit whether to initialize <i>lazy-init singletons</i> and
188+
* <i>objects created by FactoryBeans</i> (or by factory methods with a
189+
* "factory-bean" reference) for the type check. Note that FactoryBeans need to be
190+
* eagerly initialized to determine their type: So be aware that passing in "true"
191+
* for this flag will initialize FactoryBeans and "factory-bean" references.
192+
* @param type the type that beans must match (as a {@code ResolvableType})
193+
* @return the array of matching bean names, or an empty array if none
194+
* @since 5.2
195+
* @see ListableBeanFactory#getBeanNamesForType(ResolvableType, boolean, boolean)
196+
*/
197+
public static String[] beanNamesForTypeIncludingAncestors(
198+
ListableBeanFactory lbf, ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
199+
200+
Assert.notNull(lbf, "ListableBeanFactory must not be null");
201+
String[] result = lbf.getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
202+
if (lbf instanceof HierarchicalBeanFactory) {
203+
HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf;
204+
if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) {
205+
String[] parentResult = beanNamesForTypeIncludingAncestors(
206+
(ListableBeanFactory) hbf.getParentBeanFactory(), type, includeNonSingletons, allowEagerInit);
207+
result = mergeNamesWithParent(result, parentResult, hbf);
208+
}
209+
}
210+
return result;
211+
}
212+
175213
/**
176214
* Get all bean names for the given type, including those defined in ancestor
177215
* factories. Will return unique names in case of overridden bean definitions.

spring-beans/src/main/java/org/springframework/beans/factory/ListableBeanFactory.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,40 @@ public interface ListableBeanFactory extends BeanFactory {
116116
*/
117117
String[] getBeanNamesForType(ResolvableType type);
118118

119+
/**
120+
* Return the names of beans matching the given type (including subclasses),
121+
* judging from either bean definitions or the value of {@code getObjectType}
122+
* in the case of FactoryBeans.
123+
* <p><b>NOTE: This method introspects top-level beans only.</b> It does <i>not</i>
124+
* check nested beans which might match the specified type as well.
125+
* <p>Does consider objects created by FactoryBeans if the "allowEagerInit" flag is set,
126+
* which means that FactoryBeans will get initialized. If the object created by the
127+
* FactoryBean doesn't match, the raw FactoryBean itself will be matched against the
128+
* type. If "allowEagerInit" is not set, only raw FactoryBeans will be checked
129+
* (which doesn't require initialization of each FactoryBean).
130+
* <p>Does not consider any hierarchy this factory may participate in.
131+
* Use BeanFactoryUtils' {@code beanNamesForTypeIncludingAncestors}
132+
* to include beans in ancestor factories too.
133+
* <p>Note: Does <i>not</i> ignore singleton beans that have been registered
134+
* by other means than bean definitions.
135+
* <p>Bean names returned by this method should always return bean names <i>in the
136+
* order of definition</i> in the backend configuration, as far as possible.
137+
* @param type the generically typed class or interface to match
138+
* @param includeNonSingletons whether to include prototype or scoped beans too
139+
* or just singletons (also applies to FactoryBeans)
140+
* @param allowEagerInit whether to initialize <i>lazy-init singletons</i> and
141+
* <i>objects created by FactoryBeans</i> (or by factory methods with a
142+
* "factory-bean" reference) for the type check. Note that FactoryBeans need to be
143+
* eagerly initialized to determine their type: So be aware that passing in "true"
144+
* for this flag will initialize FactoryBeans and "factory-bean" references.
145+
* @return the names of beans (or objects created by FactoryBeans) matching
146+
* the given object type (including subclasses), or an empty array if none
147+
* @since 5.2
148+
* @see FactoryBean#getObjectType
149+
* @see BeanFactoryUtils#beanNamesForTypeIncludingAncestors(ListableBeanFactory, ResolvableType, boolean, boolean)
150+
*/
151+
String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit);
152+
119153
/**
120154
* Return the names of beans matching the given type (including subclasses),
121155
* judging from either bean definitions or the value of {@code getObjectType}

spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -463,12 +463,17 @@ public String[] getBeanDefinitionNames() {
463463

464464
@Override
465465
public String[] getBeanNamesForType(ResolvableType type) {
466+
return getBeanNamesForType(type, true, true);
467+
}
468+
469+
@Override
470+
public String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
466471
Class<?> resolved = type.resolve();
467472
if (resolved != null && !type.hasGenerics()) {
468-
return getBeanNamesForType(resolved, true, true);
473+
return getBeanNamesForType(resolved, includeNonSingletons, includeNonSingletons);
469474
}
470475
else {
471-
return doGetBeanNamesForType(type, true, true);
476+
return doGetBeanNamesForType(type, includeNonSingletons, includeNonSingletons);
472477
}
473478
}
474479

spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 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.
@@ -329,26 +329,32 @@ public String[] getBeanDefinitionNames() {
329329

330330
@Override
331331
public String[] getBeanNamesForType(@Nullable ResolvableType type) {
332-
boolean isFactoryType = false;
333-
if (type != null) {
334-
Class<?> resolved = type.resolve();
335-
if (resolved != null && FactoryBean.class.isAssignableFrom(resolved)) {
336-
isFactoryType = true;
337-
}
338-
}
332+
return getBeanNamesForType(type, true, true);
333+
}
334+
335+
336+
@Override
337+
public String[] getBeanNamesForType(@Nullable ResolvableType type,
338+
boolean includeNonSingletons, boolean allowEagerInit) {
339+
340+
Class<?> resolved = (type != null ? type.resolve() : null);
341+
boolean isFactoryType = resolved != null && FactoryBean.class.isAssignableFrom(resolved);
339342
List<String> matches = new ArrayList<>();
343+
340344
for (Map.Entry<String, Object> entry : this.beans.entrySet()) {
341-
String name = entry.getKey();
345+
String beanName = entry.getKey();
342346
Object beanInstance = entry.getValue();
343347
if (beanInstance instanceof FactoryBean && !isFactoryType) {
344-
Class<?> objectType = ((FactoryBean<?>) beanInstance).getObjectType();
345-
if (objectType != null && (type == null || type.isAssignableFrom(objectType))) {
346-
matches.add(name);
348+
FactoryBean<?> factoryBean = (FactoryBean<?>) beanInstance;
349+
Class<?> objectType = factoryBean.getObjectType();
350+
if ((includeNonSingletons || factoryBean.isSingleton()) &&
351+
objectType != null && (type == null || type.isAssignableFrom(objectType))) {
352+
matches.add(beanName);
347353
}
348354
}
349355
else {
350356
if (type == null || type.isInstance(beanInstance)) {
351-
matches.add(name);
357+
matches.add(beanName);
352358
}
353359
}
354360
}
@@ -362,7 +368,7 @@ public String[] getBeanNamesForType(@Nullable Class<?> type) {
362368

363369
@Override
364370
public String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
365-
return getBeanNamesForType(ResolvableType.forClass(type));
371+
return getBeanNamesForType(ResolvableType.forClass(type), includeNonSingletons, allowEagerInit);
366372
}
367373

368374
@Override

spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1751,6 +1751,8 @@ public void testGetBeanWithArgsNotCreatedForFactoryBeanChecking() {
17511751
assertThat(lbf.getBeanNamesForType(ConstructorDependencyFactoryBean.class).length).isEqualTo(1);
17521752
assertThat(lbf.getBeanNamesForType(ResolvableType.forClassWithGenerics(FactoryBean.class, Object.class)).length).isEqualTo(1);
17531753
assertThat(lbf.getBeanNamesForType(ResolvableType.forClassWithGenerics(FactoryBean.class, String.class)).length).isEqualTo(0);
1754+
assertThat(lbf.getBeanNamesForType(ResolvableType.forClassWithGenerics(FactoryBean.class, Object.class), true, true).length).isEqualTo(1);
1755+
assertThat(lbf.getBeanNamesForType(ResolvableType.forClassWithGenerics(FactoryBean.class, String.class), true, true).length).isEqualTo(0);
17541756
}
17551757

17561758
private RootBeanDefinition createConstructorDependencyBeanDefinition(int age) {

spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1208,6 +1208,12 @@ public String[] getBeanNamesForType(ResolvableType type) {
12081208
return getBeanFactory().getBeanNamesForType(type);
12091209
}
12101210

1211+
@Override
1212+
public String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
1213+
assertBeanFactoryActive();
1214+
return getBeanFactory().getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
1215+
}
1216+
12111217
@Override
12121218
public String[] getBeanNamesForType(@Nullable Class<?> type) {
12131219
assertBeanFactoryActive();

spring-test/src/main/java/org/springframework/test/web/servlet/setup/StubWebApplicationContext.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,11 @@ public String[] getBeanNamesForType(@Nullable ResolvableType type) {
251251
return this.beanFactory.getBeanNamesForType(type);
252252
}
253253

254+
@Override
255+
public String[] getBeanNamesForType(@Nullable ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
256+
return this.beanFactory.getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
257+
}
258+
254259
@Override
255260
public String[] getBeanNamesForType(@Nullable Class<?> type) {
256261
return this.beanFactory.getBeanNamesForType(type);

0 commit comments

Comments
 (0)