Skip to content

Commit 2e4ca41

Browse files
committed
Add getBeanProvider(ParameterizedTypeReference) overload
Closes gh-31444
1 parent 6503f35 commit 2e4ca41

File tree

7 files changed

+52
-3
lines changed

7 files changed

+52
-3
lines changed

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.jspecify.annotations.Nullable;
2020

2121
import org.springframework.beans.BeansException;
22+
import org.springframework.core.ParameterizedTypeReference;
2223
import org.springframework.core.ResolvableType;
2324

2425
/**
@@ -264,6 +265,22 @@ public interface BeanFactory {
264265
*/
265266
<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
266267

268+
/**
269+
* Return a provider for the specified bean, allowing for lazy on-demand retrieval
270+
* of instances, including availability and uniqueness options. This variant allows
271+
* for specifying a generic type to match, similar to reflective injection points
272+
* with generic type declarations in method/constructor parameters.
273+
* <p>This is a variant of {@link #getBeanProvider(ResolvableType)} with a
274+
* captured generic type for type-safe retrieval, typically used inline:
275+
* {@code getBeanProvider(new ParameterizedTypeReference<>() {})} - and
276+
* effectively equivalent to {@code getBeanProvider(ResolvableType.forType(...))}.
277+
* @return a corresponding provider handle
278+
* @param requiredType a captured generic type that the bean must match
279+
* @since 7.0
280+
* @see #getBeanProvider(ResolvableType)
281+
*/
282+
<T> ObjectProvider<T> getBeanProvider(ParameterizedTypeReference<T> requiredType);
283+
267284
/**
268285
* Does this bean factory contain a bean definition or externally registered singleton
269286
* instance with the given name?

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
import org.springframework.core.NamedThreadLocal;
7979
import org.springframework.core.OrderComparator;
8080
import org.springframework.core.Ordered;
81+
import org.springframework.core.ParameterizedTypeReference;
8182
import org.springframework.core.ResolvableType;
8283
import org.springframework.core.SpringProperties;
8384
import org.springframework.core.annotation.MergedAnnotation;
@@ -398,6 +399,10 @@ public <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType) {
398399
return getBeanProvider(requiredType, true);
399400
}
400401

402+
public <T> ObjectProvider<T> getBeanProvider(ParameterizedTypeReference<T> requiredType) {
403+
return getBeanProvider(ResolvableType.forType(requiredType), true);
404+
}
405+
401406

402407
//---------------------------------------------------------------------
403408
// Implementation of ListableBeanFactory interface

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
4040
import org.springframework.beans.factory.ObjectProvider;
4141
import org.springframework.beans.factory.SmartFactoryBean;
42+
import org.springframework.core.ParameterizedTypeReference;
4243
import org.springframework.core.ResolvableType;
4344
import org.springframework.core.annotation.AnnotatedElementUtils;
4445
import org.springframework.util.Assert;
@@ -199,6 +200,11 @@ public <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType) {
199200
return getBeanProvider(requiredType, true);
200201
}
201202

203+
@Override
204+
public <T> ObjectProvider<T> getBeanProvider(ParameterizedTypeReference<T> requiredType) {
205+
return getBeanProvider(ResolvableType.forType(requiredType), true);
206+
}
207+
202208
@Override
203209
public boolean containsBean(String name) {
204210
return this.beans.containsKey(name);

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import org.springframework.beans.testfixture.beans.GenericSetOfIntegerBean;
4646
import org.springframework.beans.testfixture.beans.TestBean;
4747
import org.springframework.core.OverridingClassLoader;
48+
import org.springframework.core.ParameterizedTypeReference;
4849
import org.springframework.core.ResolvableType;
4950
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
5051
import org.springframework.core.annotation.Order;
@@ -792,9 +793,9 @@ void genericMatchingWithFullTypeDifferentiation(Class<?> factoryClass) {
792793
assertThat(doubleStoreNames).containsExactly("store1");
793794
assertThat(floatStoreNames).containsExactly("store2");
794795

795-
ObjectProvider<NumberStore<?>> numberStoreProvider = bf.getBeanProvider(ResolvableType.forClass(NumberStore.class));
796-
ObjectProvider<NumberStore<Double>> doubleStoreProvider = bf.getBeanProvider(ResolvableType.forClassWithGenerics(NumberStore.class, Double.class));
797-
ObjectProvider<NumberStore<Float>> floatStoreProvider = bf.getBeanProvider(ResolvableType.forClassWithGenerics(NumberStore.class, Float.class));
796+
ObjectProvider<NumberStore<?>> numberStoreProvider = bf.getBeanProvider(new ParameterizedTypeReference<>() {});
797+
ObjectProvider<NumberStore<Double>> doubleStoreProvider = bf.getBeanProvider(new ParameterizedTypeReference<>() {});
798+
ObjectProvider<NumberStore<Float>> floatStoreProvider = bf.getBeanProvider(new ParameterizedTypeReference<>() {});
798799
assertThatExceptionOfType(NoUniqueBeanDefinitionException.class).isThrownBy(numberStoreProvider::getObject);
799800
assertThatExceptionOfType(NoUniqueBeanDefinitionException.class).isThrownBy(numberStoreProvider::getIfAvailable);
800801
assertThat(numberStoreProvider.getIfUnique()).isNull();

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
import org.springframework.context.weaving.LoadTimeWeaverAware;
7777
import org.springframework.context.weaving.LoadTimeWeaverAwareProcessor;
7878
import org.springframework.core.NativeDetector;
79+
import org.springframework.core.ParameterizedTypeReference;
7980
import org.springframework.core.ResolvableType;
8081
import org.springframework.core.annotation.AnnotationUtils;
8182
import org.springframework.core.convert.ConversionService;
@@ -1303,6 +1304,12 @@ public <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType) {
13031304
return getBeanFactory().getBeanProvider(requiredType);
13041305
}
13051306

1307+
@Override
1308+
public <T> ObjectProvider<T> getBeanProvider(ParameterizedTypeReference<T> requiredType) {
1309+
assertBeanFactoryActive();
1310+
return getBeanFactory().getBeanProvider(requiredType);
1311+
}
1312+
13061313
@Override
13071314
public boolean containsBean(String name) {
13081315
return getBeanFactory().containsBean(name);

spring-context/src/main/java/org/springframework/jndi/support/SimpleJndiBeanFactory.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
3535
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
3636
import org.springframework.beans.factory.ObjectProvider;
37+
import org.springframework.core.ParameterizedTypeReference;
3738
import org.springframework.core.ResolvableType;
3839
import org.springframework.jndi.JndiLocatorSupport;
3940
import org.springframework.jndi.TypeMismatchNamingException;
@@ -195,6 +196,12 @@ public <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType) {
195196
"SimpleJndiBeanFactory does not support resolution by ResolvableType");
196197
}
197198

199+
@Override
200+
public <T> ObjectProvider<T> getBeanProvider(ParameterizedTypeReference<T> requiredType) {
201+
throw new UnsupportedOperationException(
202+
"SimpleJndiBeanFactory does not support resolution by ParameterizedTypeReference");
203+
}
204+
198205
@Override
199206
public boolean containsBean(String name) {
200207
if (this.singletonObjects.containsKey(name) || this.resourceTypes.containsKey(name)) {

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import org.springframework.context.MessageSourceResolvable;
4444
import org.springframework.context.NoSuchMessageException;
4545
import org.springframework.context.support.DelegatingMessageSource;
46+
import org.springframework.core.ParameterizedTypeReference;
4647
import org.springframework.core.ResolvableType;
4748
import org.springframework.core.env.Environment;
4849
import org.springframework.core.env.StandardEnvironment;
@@ -192,6 +193,11 @@ public <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType) {
192193
return this.beanFactory.getBeanProvider(requiredType);
193194
}
194195

196+
@Override
197+
public <T> ObjectProvider<T> getBeanProvider(ParameterizedTypeReference<T> requiredType) {
198+
return this.beanFactory.getBeanProvider(requiredType);
199+
}
200+
195201
@Override
196202
public boolean containsBean(String name) {
197203
return this.beanFactory.containsBean(name);

0 commit comments

Comments
 (0)