Browse Source

Add getBeanProvider(ParameterizedTypeReference) overload

Closes gh-31444
pull/35649/head
Juergen Hoeller 2 months ago
parent
commit
2e4ca41382
  1. 17
      spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java
  2. 5
      spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
  3. 6
      spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java
  4. 7
      spring-beans/src/test/java/org/springframework/beans/factory/support/BeanFactoryGenericsTests.java
  5. 7
      spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java
  6. 7
      spring-context/src/main/java/org/springframework/jndi/support/SimpleJndiBeanFactory.java
  7. 6
      spring-test/src/main/java/org/springframework/test/web/servlet/setup/StubWebApplicationContext.java

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

@ -19,6 +19,7 @@ package org.springframework.beans.factory; @@ -19,6 +19,7 @@ package org.springframework.beans.factory;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.BeansException;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.ResolvableType;
/**
@ -264,6 +265,22 @@ public interface BeanFactory { @@ -264,6 +265,22 @@ public interface BeanFactory {
*/
<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
/**
* Return a provider for the specified bean, allowing for lazy on-demand retrieval
* of instances, including availability and uniqueness options. This variant allows
* for specifying a generic type to match, similar to reflective injection points
* with generic type declarations in method/constructor parameters.
* <p>This is a variant of {@link #getBeanProvider(ResolvableType)} with a
* captured generic type for type-safe retrieval, typically used inline:
* {@code getBeanProvider(new ParameterizedTypeReference<>() {})} - and
* effectively equivalent to {@code getBeanProvider(ResolvableType.forType(...))}.
* @return a corresponding provider handle
* @param requiredType a captured generic type that the bean must match
* @since 7.0
* @see #getBeanProvider(ResolvableType)
*/
<T> ObjectProvider<T> getBeanProvider(ParameterizedTypeReference<T> requiredType);
/**
* Does this bean factory contain a bean definition or externally registered singleton
* instance with the given name?

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

@ -78,6 +78,7 @@ import org.springframework.beans.factory.config.NamedBeanHolder; @@ -78,6 +78,7 @@ import org.springframework.beans.factory.config.NamedBeanHolder;
import org.springframework.core.NamedThreadLocal;
import org.springframework.core.OrderComparator;
import org.springframework.core.Ordered;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.ResolvableType;
import org.springframework.core.SpringProperties;
import org.springframework.core.annotation.MergedAnnotation;
@ -398,6 +399,10 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto @@ -398,6 +399,10 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
return getBeanProvider(requiredType, true);
}
public <T> ObjectProvider<T> getBeanProvider(ParameterizedTypeReference<T> requiredType) {
return getBeanProvider(ResolvableType.forType(requiredType), true);
}
//---------------------------------------------------------------------
// Implementation of ListableBeanFactory interface

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

@ -39,6 +39,7 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException; @@ -39,6 +39,7 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.SmartFactoryBean;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.util.Assert;
@ -199,6 +200,11 @@ public class StaticListableBeanFactory implements ListableBeanFactory { @@ -199,6 +200,11 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
return getBeanProvider(requiredType, true);
}
@Override
public <T> ObjectProvider<T> getBeanProvider(ParameterizedTypeReference<T> requiredType) {
return getBeanProvider(ResolvableType.forType(requiredType), true);
}
@Override
public boolean containsBean(String name) {
return this.beans.containsKey(name);

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

@ -45,6 +45,7 @@ import org.springframework.beans.testfixture.beans.GenericIntegerBean; @@ -45,6 +45,7 @@ import org.springframework.beans.testfixture.beans.GenericIntegerBean;
import org.springframework.beans.testfixture.beans.GenericSetOfIntegerBean;
import org.springframework.beans.testfixture.beans.TestBean;
import org.springframework.core.OverridingClassLoader;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.annotation.Order;
@ -792,9 +793,9 @@ class BeanFactoryGenericsTests { @@ -792,9 +793,9 @@ class BeanFactoryGenericsTests {
assertThat(doubleStoreNames).containsExactly("store1");
assertThat(floatStoreNames).containsExactly("store2");
ObjectProvider<NumberStore<?>> numberStoreProvider = bf.getBeanProvider(ResolvableType.forClass(NumberStore.class));
ObjectProvider<NumberStore<Double>> doubleStoreProvider = bf.getBeanProvider(ResolvableType.forClassWithGenerics(NumberStore.class, Double.class));
ObjectProvider<NumberStore<Float>> floatStoreProvider = bf.getBeanProvider(ResolvableType.forClassWithGenerics(NumberStore.class, Float.class));
ObjectProvider<NumberStore<?>> numberStoreProvider = bf.getBeanProvider(new ParameterizedTypeReference<>() {});
ObjectProvider<NumberStore<Double>> doubleStoreProvider = bf.getBeanProvider(new ParameterizedTypeReference<>() {});
ObjectProvider<NumberStore<Float>> floatStoreProvider = bf.getBeanProvider(new ParameterizedTypeReference<>() {});
assertThatExceptionOfType(NoUniqueBeanDefinitionException.class).isThrownBy(numberStoreProvider::getObject);
assertThatExceptionOfType(NoUniqueBeanDefinitionException.class).isThrownBy(numberStoreProvider::getIfAvailable);
assertThat(numberStoreProvider.getIfUnique()).isNull();

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

@ -76,6 +76,7 @@ import org.springframework.context.expression.StandardBeanExpressionResolver; @@ -76,6 +76,7 @@ import org.springframework.context.expression.StandardBeanExpressionResolver;
import org.springframework.context.weaving.LoadTimeWeaverAware;
import org.springframework.context.weaving.LoadTimeWeaverAwareProcessor;
import org.springframework.core.NativeDetector;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.convert.ConversionService;
@ -1303,6 +1304,12 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader @@ -1303,6 +1304,12 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
return getBeanFactory().getBeanProvider(requiredType);
}
@Override
public <T> ObjectProvider<T> getBeanProvider(ParameterizedTypeReference<T> requiredType) {
assertBeanFactoryActive();
return getBeanFactory().getBeanProvider(requiredType);
}
@Override
public boolean containsBean(String name) {
return getBeanFactory().containsBean(name);

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

@ -34,6 +34,7 @@ import org.springframework.beans.factory.BeanNotOfRequiredTypeException; @@ -34,6 +34,7 @@ import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.ResolvableType;
import org.springframework.jndi.JndiLocatorSupport;
import org.springframework.jndi.TypeMismatchNamingException;
@ -195,6 +196,12 @@ public class SimpleJndiBeanFactory extends JndiLocatorSupport implements BeanFac @@ -195,6 +196,12 @@ public class SimpleJndiBeanFactory extends JndiLocatorSupport implements BeanFac
"SimpleJndiBeanFactory does not support resolution by ResolvableType");
}
@Override
public <T> ObjectProvider<T> getBeanProvider(ParameterizedTypeReference<T> requiredType) {
throw new UnsupportedOperationException(
"SimpleJndiBeanFactory does not support resolution by ParameterizedTypeReference");
}
@Override
public boolean containsBean(String name) {
if (this.singletonObjects.containsKey(name) || this.resourceTypes.containsKey(name)) {

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

@ -43,6 +43,7 @@ import org.springframework.context.MessageSource; @@ -43,6 +43,7 @@ import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceResolvable;
import org.springframework.context.NoSuchMessageException;
import org.springframework.context.support.DelegatingMessageSource;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.ResolvableType;
import org.springframework.core.env.Environment;
import org.springframework.core.env.StandardEnvironment;
@ -192,6 +193,11 @@ class StubWebApplicationContext implements WebApplicationContext { @@ -192,6 +193,11 @@ class StubWebApplicationContext implements WebApplicationContext {
return this.beanFactory.getBeanProvider(requiredType);
}
@Override
public <T> ObjectProvider<T> getBeanProvider(ParameterizedTypeReference<T> requiredType) {
return this.beanFactory.getBeanProvider(requiredType);
}
@Override
public boolean containsBean(String name) {
return this.beanFactory.containsBean(name);

Loading…
Cancel
Save