diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/BeanRegistry.java b/spring-beans/src/main/java/org/springframework/beans/factory/BeanRegistry.java
index a9beddaf545..3348da86fd8 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/BeanRegistry.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/BeanRegistry.java
@@ -24,7 +24,6 @@ import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
-import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.ResolvableType;
import org.springframework.core.env.Environment;
@@ -55,43 +54,92 @@ public interface BeanRegistry {
void registerAlias(String name, String alias);
/**
- * Register a bean from the given bean class, which will be instantiated using the
+ * Register a bean from the given class, which will be instantiated using the
* related {@link BeanUtils#getResolvableConstructor resolvable constructor} if any.
+ *
For registering a bean with a generic type, consider
+ * {@link #registerBean(ParameterizedTypeReference)}.
* @param beanClass the class of the bean
* @return the generated bean name
+ * @see #registerBean(Class)
*/
String registerBean(Class beanClass);
/**
- * Register a bean from the given bean class, customizing it with the customizer
+ * Register a bean from the given generics-containing type, which will be
+ * instantiated using the related
+ * {@link BeanUtils#getResolvableConstructor resolvable constructor} if any.
+ * @param beanType the generics-containing type of the bean
+ * @return the generated bean name
+ */
+ String registerBean(ParameterizedTypeReference beanType);
+
+ /**
+ * Register a bean from the given class, customizing it with the customizer
* callback. The bean will be instantiated using the supplier that can be configured
* in the customizer callback, or will be tentatively instantiated with its
* {@link BeanUtils#getResolvableConstructor resolvable constructor} otherwise.
+ * For registering a bean with a generic type, consider
+ * {@link #registerBean(ParameterizedTypeReference, Consumer)}.
* @param beanClass the class of the bean
- * @param customizer callback to customize other bean properties than the name
+ * @param customizer the callback to customize other bean properties than the name
* @return the generated bean name
*/
String registerBean(Class beanClass, Consumer> customizer);
/**
- * Register a bean from the given bean class, which will be instantiated using the
+ * Register a bean from the given generics-containing type, customizing it
+ * with the customizer callback. The bean will be instantiated using the supplier
+ * that can be configured in the customizer callback, or will be tentatively instantiated
+ * with its {@link BeanUtils#getResolvableConstructor resolvable constructor} otherwise.
+ * @param beanType the generics-containing type of the bean
+ * @param customizer the callback to customize other bean properties than the name
+ * @return the generated bean name
+ */
+ String registerBean(ParameterizedTypeReference beanType, Consumer> customizer);
+
+ /**
+ * Register a bean from the given class, which will be instantiated using the
* related {@link BeanUtils#getResolvableConstructor resolvable constructor} if any.
+ * For registering a bean with a generic type, consider
+ * {@link #registerBean(String, ParameterizedTypeReference)}.
* @param name the name of the bean
* @param beanClass the class of the bean
*/
void registerBean(String name, Class beanClass);
/**
- * Register a bean from the given bean class, customizing it with the customizer
+ * Register a bean from the given generics-containing type, which
+ * will be instantiated using the related
+ * {@link BeanUtils#getResolvableConstructor resolvable constructor} if any.
+ * @param name the name of the bean
+ * @param beanType the generics-containing type of the bean
+ */
+ void registerBean(String name, ParameterizedTypeReference beanType);
+
+ /**
+ * Register a bean from the given class, customizing it with the customizer
* callback. The bean will be instantiated using the supplier that can be configured
* in the customizer callback, or will be tentatively instantiated with its
* {@link BeanUtils#getResolvableConstructor resolvable constructor} otherwise.
+ * For registering a bean with a generic type, consider
+ * {@link #registerBean(String, ParameterizedTypeReference, Consumer)}.
* @param name the name of the bean
* @param beanClass the class of the bean
- * @param customizer callback to customize other bean properties than the name
+ * @param customizer the callback to customize other bean properties than the name
*/
void registerBean(String name, Class beanClass, Consumer> customizer);
+ /**
+ * Register a bean from the given generics-containing type, customizing it
+ * with the customizer callback. The bean will be instantiated using the supplier
+ * that can be configured in the customizer callback, or will be tentatively instantiated
+ * with its {@link BeanUtils#getResolvableConstructor resolvable constructor} otherwise.
+ * @param name the name of the bean
+ * @param beanType the generics-containing type of the bean
+ * @param customizer the callback to customize other bean properties than the name
+ */
+ void registerBean(String name, ParameterizedTypeReference beanType, Consumer> customizer);
+
/**
* Specification for customizing a bean.
@@ -164,20 +212,6 @@ public interface BeanRegistry {
* @see AbstractBeanDefinition#setInstanceSupplier(Supplier)
*/
Spec supplier(Function supplier);
-
- /**
- * Set a generics-containing target type of this bean.
- * @see #targetType(ResolvableType)
- * @see RootBeanDefinition#setTargetType(ResolvableType)
- */
- Spec targetType(ParameterizedTypeReference extends T> type);
-
- /**
- * Set a generics-containing target type of this bean.
- * @see #targetType(ParameterizedTypeReference)
- * @see RootBeanDefinition#setTargetType(ResolvableType)
- */
- Spec targetType(ResolvableType type);
}
@@ -188,32 +222,40 @@ public interface BeanRegistry {
interface SupplierContext {
/**
- * Return the bean instance that uniquely matches the given object type, if any.
- * @param requiredType type the bean must match; can be an interface or superclass
- * @return an instance of the single bean matching the required type
+ * Return the bean instance that uniquely matches the given type, if any.
+ * @param beanClass the type the bean must match; can be an interface or superclass
+ * @return an instance of the single bean matching the bean type
+ * @see BeanFactory#getBean(String)
+ */
+ T bean(Class beanClass) throws BeansException;
+
+ /**
+ * Return the bean instance that uniquely matches the given generics-containing type, if any.
+ * @param beanType the generics-containing type the bean must match; can be an interface or superclass
+ * @return an instance of the single bean matching the bean type
* @see BeanFactory#getBean(String)
*/
- T bean(Class requiredType) throws BeansException;
+ T bean(ParameterizedTypeReference beanType) throws BeansException;
/**
* Return an instance, which may be shared or independent, of the
* specified bean.
* @param name the name of the bean to retrieve
- * @param requiredType type the bean must match; can be an interface or superclass
+ * @param beanClass the type the bean must match; can be an interface or superclass
* @return an instance of the bean.
* @see BeanFactory#getBean(String, Class)
*/
- T bean(String name, Class requiredType) throws BeansException;
+ T bean(String name, Class beanClass) throws BeansException;
/**
* Return a provider for the specified bean, allowing for lazy on-demand retrieval
* of instances, including availability and uniqueness options.
- * For matching a generic type, consider {@link #beanProvider(ResolvableType)}.
- * @param requiredType type the bean must match; can be an interface or superclass
+ *
For matching a generic type, consider {@link #beanProvider(ParameterizedTypeReference)}.
+ * @param beanClass the type the bean must match; can be an interface or superclass
* @return a corresponding provider handle
* @see BeanFactory#getBeanProvider(Class)
*/
- ObjectProvider beanProvider(Class requiredType);
+ ObjectProvider beanProvider(Class beanClass);
/**
* Return a provider for the specified bean, allowing for lazy on-demand retrieval
@@ -229,11 +271,11 @@ public interface BeanRegistry {
* Java compiler warning), consider calling {@link #beanProvider(Class)} with the
* raw type as a second step if no full generic match is
* {@link ObjectProvider#getIfAvailable() available} with this variant.
- * @param requiredType type the bean must match; can be a generic type declaration
+ * @param beanType the generics-containing type the bean must match; can be an interface or superclass
* @return a corresponding provider handle
* @see BeanFactory#getBeanProvider(ResolvableType)
*/
- ObjectProvider beanProvider(ResolvableType requiredType);
+ ObjectProvider beanProvider(ParameterizedTypeReference beanType);
}
}
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanRegistryAdapter.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanRegistryAdapter.java
index 9131786e531..103c59dd2f5 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanRegistryAdapter.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanRegistryAdapter.java
@@ -17,6 +17,7 @@
package org.springframework.beans.factory.support;
import java.lang.reflect.Constructor;
+import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -92,6 +93,14 @@ public class BeanRegistryAdapter implements BeanRegistry {
return beanName;
}
+ @Override
+ public String registerBean(ParameterizedTypeReference beanType) {
+ ResolvableType resolvableType = ResolvableType.forType(beanType);
+ String beanName = BeanDefinitionReaderUtils.uniqueBeanName(Objects.requireNonNull(resolvableType.resolve()).getName(), this.beanRegistry);
+ registerBean(beanName, beanType);
+ return beanName;
+ }
+
@Override
public String registerBean(Class beanClass, Consumer> customizer) {
String beanName = BeanDefinitionReaderUtils.uniqueBeanName(beanClass.getName(), this.beanRegistry);
@@ -99,6 +108,15 @@ public class BeanRegistryAdapter implements BeanRegistry {
return beanName;
}
+ @Override
+ public String registerBean(ParameterizedTypeReference beanType, Consumer> customizer) {
+ ResolvableType resolvableType = ResolvableType.forType(beanType);
+ Class> beanClass = Objects.requireNonNull(resolvableType.resolve());
+ String beanName = BeanDefinitionReaderUtils.uniqueBeanName(beanClass.getName(), this.beanRegistry);
+ registerBean(beanName, beanType, customizer);
+ return beanName;
+ }
+
@Override
public void registerBean(String name, Class beanClass) {
BeanRegistrarBeanDefinition beanDefinition = new BeanRegistrarBeanDefinition(beanClass, this.beanRegistrarClass);
@@ -111,9 +129,11 @@ public class BeanRegistryAdapter implements BeanRegistry {
}
@Override
- public void registerBean(String name, Class beanClass, Consumer> spec) {
+ public void registerBean(String name, ParameterizedTypeReference beanType) {
+ ResolvableType resolvableType = ResolvableType.forType(beanType);
+ Class> beanClass = Objects.requireNonNull(resolvableType.resolve());
BeanRegistrarBeanDefinition beanDefinition = new BeanRegistrarBeanDefinition(beanClass, this.beanRegistrarClass);
- spec.accept(new BeanSpecAdapter<>(beanDefinition, this.beanFactory));
+ beanDefinition.setTargetType(resolvableType);
if (this.customizers != null && this.customizers.containsKey(name)) {
for (BeanDefinitionCustomizer customizer : this.customizers.get(name)) {
customizer.customize(beanDefinition);
@@ -122,6 +142,33 @@ public class BeanRegistryAdapter implements BeanRegistry {
this.beanRegistry.registerBeanDefinition(name, beanDefinition);
}
+ @Override
+ public void registerBean(String name, Class beanClass, Consumer> customizer) {
+ BeanRegistrarBeanDefinition beanDefinition = new BeanRegistrarBeanDefinition(beanClass, this.beanRegistrarClass);
+ customizer.accept(new BeanSpecAdapter<>(beanDefinition, this.beanFactory));
+ if (this.customizers != null && this.customizers.containsKey(name)) {
+ for (BeanDefinitionCustomizer registryCustomizer : this.customizers.get(name)) {
+ registryCustomizer.customize(beanDefinition);
+ }
+ }
+ this.beanRegistry.registerBeanDefinition(name, beanDefinition);
+ }
+
+ @Override
+ public void registerBean(String name, ParameterizedTypeReference beanType, Consumer> customizer) {
+ ResolvableType resolvableType = ResolvableType.forType(beanType);
+ Class> beanClass = Objects.requireNonNull(resolvableType.resolve());
+ BeanRegistrarBeanDefinition beanDefinition = new BeanRegistrarBeanDefinition(beanClass, this.beanRegistrarClass);
+ beanDefinition.setTargetType(resolvableType);
+ customizer.accept(new BeanSpecAdapter<>(beanDefinition, this.beanFactory));
+ if (this.customizers != null && this.customizers.containsKey(name)) {
+ for (BeanDefinitionCustomizer registryCustomizer : this.customizers.get(name)) {
+ registryCustomizer.customize(beanDefinition);
+ }
+ }
+ this.beanRegistry.registerBeanDefinition(name, beanDefinition);
+ }
+
@Override
public void register(BeanRegistrar registrar) {
Assert.notNull(registrar, "'registrar' must not be null");
@@ -238,18 +285,6 @@ public class BeanRegistryAdapter implements BeanRegistry {
supplier.apply(new SupplierContextAdapter(this.beanFactory)));
return this;
}
-
- @Override
- public Spec targetType(ParameterizedTypeReference extends T> targetType) {
- this.beanDefinition.setTargetType(ResolvableType.forType(targetType));
- return this;
- }
-
- @Override
- public Spec targetType(ResolvableType targetType) {
- this.beanDefinition.setTargetType(targetType);
- return this;
- }
}
@@ -262,23 +297,28 @@ public class BeanRegistryAdapter implements BeanRegistry {
}
@Override
- public T bean(Class requiredType) throws BeansException {
- return this.beanFactory.getBean(requiredType);
+ public T bean(Class beanClass) throws BeansException {
+ return this.beanFactory.getBean(beanClass);
+ }
+
+ @Override
+ public T bean(ParameterizedTypeReference beanType) throws BeansException {
+ return this.beanFactory.getBeanProvider(beanType).getObject();
}
@Override
- public T bean(String name, Class requiredType) throws BeansException {
- return this.beanFactory.getBean(name, requiredType);
+ public T bean(String name, Class beanClass) throws BeansException {
+ return this.beanFactory.getBean(name, beanClass);
}
@Override
- public ObjectProvider beanProvider(Class requiredType) {
- return this.beanFactory.getBeanProvider(requiredType);
+ public ObjectProvider beanProvider(Class beanClass) {
+ return this.beanFactory.getBeanProvider(beanClass);
}
@Override
- public ObjectProvider beanProvider(ResolvableType requiredType) {
- return this.beanFactory.getBeanProvider(requiredType);
+ public ObjectProvider beanProvider(ParameterizedTypeReference beanType) {
+ return this.beanFactory.getBeanProvider(beanType);
}
}
diff --git a/spring-beans/src/main/kotlin/org/springframework/beans/factory/BeanRegistrarDsl.kt b/spring-beans/src/main/kotlin/org/springframework/beans/factory/BeanRegistrarDsl.kt
index a6a4a56a64f..7deae838654 100644
--- a/spring-beans/src/main/kotlin/org/springframework/beans/factory/BeanRegistrarDsl.kt
+++ b/spring-beans/src/main/kotlin/org/springframework/beans/factory/BeanRegistrarDsl.kt
@@ -168,12 +168,8 @@ open class BeanRegistrarDsl(private val init: BeanRegistrarDsl.() -> Unit): Bean
if (prototype) {
it.prototype()
}
- val resolvableType = ResolvableType.forType(object: ParameterizedTypeReference() {});
- if (resolvableType.hasGenerics()) {
- it.targetType(resolvableType)
- }
}
- registry.registerBean(name, T::class.java, customizer)
+ registry.registerBean(name, object: ParameterizedTypeReference() {}, customizer)
}
/**
@@ -234,12 +230,8 @@ open class BeanRegistrarDsl(private val init: BeanRegistrarDsl.() -> Unit): Bean
if (prototype) {
it.prototype()
}
- val resolvableType = ResolvableType.forType(object: ParameterizedTypeReference() {});
- if (resolvableType.hasGenerics()) {
- it.targetType(resolvableType)
- }
}
- return registry.registerBean(T::class.java, customizer)
+ return registry.registerBean(object: ParameterizedTypeReference() {}, customizer)
}
/**
@@ -304,12 +296,8 @@ open class BeanRegistrarDsl(private val init: BeanRegistrarDsl.() -> Unit): Bean
it.supplier {
SupplierContextDsl(it, env).supplier()
}
- val resolvableType = ResolvableType.forType(object: ParameterizedTypeReference() {});
- if (resolvableType.hasGenerics()) {
- it.targetType(resolvableType)
- }
}
- registry.registerBean(name, T::class.java, customizer)
+ registry.registerBean(name, object: ParameterizedTypeReference() {}, customizer)
}
inline fun registerBean(autowirable: Boolean = true,
@@ -372,12 +360,8 @@ open class BeanRegistrarDsl(private val init: BeanRegistrarDsl.() -> Unit): Bean
it.supplier {
SupplierContextDsl(it, env).supplier()
}
- val resolvableType = ResolvableType.forType(object: ParameterizedTypeReference() {});
- if (resolvableType.hasGenerics()) {
- it.targetType(resolvableType)
- }
}
- return registry.registerBean(T::class.java, customizer)
+ return registry.registerBean(object: ParameterizedTypeReference() {}, customizer)
}
// Function with 0 parameter
@@ -1094,7 +1078,7 @@ open class BeanRegistrarDsl(private val init: BeanRegistrarDsl.() -> Unit): Bean
* @return a corresponding provider handle
*/
inline fun beanProvider() : ObjectProvider =
- context.beanProvider(ResolvableType.forType((object : ParameterizedTypeReference() {}).type))
+ context.beanProvider(object : ParameterizedTypeReference() {})
}
override fun register(registry: BeanRegistry, env: Environment) {
diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/support/BeanRegistryAdapterTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/support/BeanRegistryAdapterTests.java
index 51461235a88..c1ceba10796 100644
--- a/spring-beans/src/test/java/org/springframework/beans/factory/support/BeanRegistryAdapterTests.java
+++ b/spring-beans/src/test/java/org/springframework/beans/factory/support/BeanRegistryAdapterTests.java
@@ -24,7 +24,6 @@ import org.springframework.beans.factory.BeanRegistrar;
import org.springframework.beans.factory.BeanRegistry;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.core.ParameterizedTypeReference;
-import org.springframework.core.ResolvableType;
import org.springframework.core.env.Environment;
import org.springframework.core.env.StandardEnvironment;
@@ -206,18 +205,10 @@ public class BeanRegistryAdapterTests {
}
@Test
- void customTargetTypeFromResolvableType() {
- BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, env, TargetTypeBeanRegistrar.class);
- new TargetTypeBeanRegistrar().register(adapter, env);
- RootBeanDefinition beanDefinition = (RootBeanDefinition)this.beanFactory.getBeanDefinition("fooSupplierFromResolvableType");
- assertThat(beanDefinition.getResolvableType().resolveGeneric(0)).isEqualTo(Foo.class);
- }
-
- @Test
- void customTargetTypeFromTypeReference() {
- BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, env, TargetTypeBeanRegistrar.class);
- new TargetTypeBeanRegistrar().register(adapter, env);
- RootBeanDefinition beanDefinition = (RootBeanDefinition)this.beanFactory.getBeanDefinition("fooSupplierFromTypeReference");
+ void genericType() {
+ BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, env, GenericTypeBeanRegistrar.class);
+ new GenericTypeBeanRegistrar().register(adapter, env);
+ RootBeanDefinition beanDefinition = (RootBeanDefinition)this.beanFactory.getBeanDefinition("fooSupplier");
assertThat(beanDefinition.getResolvableType().resolveGeneric(0)).isEqualTo(Foo.class);
}
@@ -325,15 +316,11 @@ public class BeanRegistryAdapterTests {
}
}
- private static class TargetTypeBeanRegistrar implements BeanRegistrar {
+ private static class GenericTypeBeanRegistrar implements BeanRegistrar {
@Override
public void register(BeanRegistry registry, Environment env) {
- registry.registerBean("fooSupplierFromResolvableType", Foo.class,
- spec -> spec.targetType(ResolvableType.forClassWithGenerics(Supplier.class, Foo.class)));
- ParameterizedTypeReference> type = new ParameterizedTypeReference<>() {};
- registry.registerBean("fooSupplierFromTypeReference", Supplier.class,
- spec -> spec.targetType(type));
+ registry.registerBean("fooSupplier", new ParameterizedTypeReference>() {});
}
}
diff --git a/spring-context/src/testFixtures/java/org/springframework/context/testfixture/beans/factory/GenericBeanRegistrar.java b/spring-context/src/testFixtures/java/org/springframework/context/testfixture/beans/factory/GenericBeanRegistrar.java
index 4f1801d3034..b732d9a2179 100644
--- a/spring-context/src/testFixtures/java/org/springframework/context/testfixture/beans/factory/GenericBeanRegistrar.java
+++ b/spring-context/src/testFixtures/java/org/springframework/context/testfixture/beans/factory/GenericBeanRegistrar.java
@@ -27,9 +27,8 @@ public class GenericBeanRegistrar implements BeanRegistrar {
@Override
public void register(BeanRegistry registry, Environment env) {
- ParameterizedTypeReference> type = new ParameterizedTypeReference<>() {};
- registry.registerBean("fooSupplier", Supplier.class, spec -> spec.targetType(type)
- .supplier(context-> (Supplier) Foo::new));
+ registry.registerBean("fooSupplier", new ParameterizedTypeReference>() {}, spec ->
+ spec.supplier(context-> (Supplier) Foo::new));
}
public record Foo() {}