Skip to content

Commit b46c41b

Browse files
committed
Add first class ParameterizedTypeReference support to BeanRegistrar
This commit replaces ParameterizedTypeReference and ResolvableType target type customization with the lambda by directly exposing ParameterizedTypeReference methods at top level, as generics variants of the class-based existing ones. Closes gh-35635
1 parent e6481a0 commit b46c41b

File tree

5 files changed

+149
-97
lines changed

5 files changed

+149
-97
lines changed

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

Lines changed: 74 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import org.springframework.beans.BeansException;
2525
import org.springframework.beans.factory.config.BeanDefinition;
2626
import org.springframework.beans.factory.support.AbstractBeanDefinition;
27-
import org.springframework.beans.factory.support.RootBeanDefinition;
2827
import org.springframework.core.ParameterizedTypeReference;
2928
import org.springframework.core.ResolvableType;
3029
import org.springframework.core.env.Environment;
@@ -55,43 +54,92 @@ public interface BeanRegistry {
5554
void registerAlias(String name, String alias);
5655

5756
/**
58-
* Register a bean from the given bean class, which will be instantiated using the
57+
* Register a bean from the given class, which will be instantiated using the
5958
* related {@link BeanUtils#getResolvableConstructor resolvable constructor} if any.
59+
* <p>For registering a bean with a generic type, consider
60+
* {@link #registerBean(ParameterizedTypeReference)}.
6061
* @param beanClass the class of the bean
6162
* @return the generated bean name
63+
* @see #registerBean(Class)
6264
*/
6365
<T> String registerBean(Class<T> beanClass);
6466

6567
/**
66-
* Register a bean from the given bean class, customizing it with the customizer
68+
* Register a bean from the given generics-containing type, which will be
69+
* instantiated using the related
70+
* {@link BeanUtils#getResolvableConstructor resolvable constructor} if any.
71+
* @param beanType the generics-containing type of the bean
72+
* @return the generated bean name
73+
*/
74+
<T> String registerBean(ParameterizedTypeReference<T> beanType);
75+
76+
/**
77+
* Register a bean from the given class, customizing it with the customizer
6778
* callback. The bean will be instantiated using the supplier that can be configured
6879
* in the customizer callback, or will be tentatively instantiated with its
6980
* {@link BeanUtils#getResolvableConstructor resolvable constructor} otherwise.
81+
* <p>For registering a bean with a generic type, consider
82+
* {@link #registerBean(ParameterizedTypeReference, Consumer)}.
7083
* @param beanClass the class of the bean
71-
* @param customizer callback to customize other bean properties than the name
84+
* @param customizer the callback to customize other bean properties than the name
7285
* @return the generated bean name
7386
*/
7487
<T> String registerBean(Class<T> beanClass, Consumer<Spec<T>> customizer);
7588

7689
/**
77-
* Register a bean from the given bean class, which will be instantiated using the
90+
* Register a bean from the given generics-containing type, customizing it
91+
* with the customizer callback. The bean will be instantiated using the supplier
92+
* that can be configured in the customizer callback, or will be tentatively instantiated
93+
* with its {@link BeanUtils#getResolvableConstructor resolvable constructor} otherwise.
94+
* @param beanType the generics-containing type of the bean
95+
* @param customizer the callback to customize other bean properties than the name
96+
* @return the generated bean name
97+
*/
98+
<T> String registerBean(ParameterizedTypeReference<T> beanType, Consumer<Spec<T>> customizer);
99+
100+
/**
101+
* Register a bean from the given class, which will be instantiated using the
78102
* related {@link BeanUtils#getResolvableConstructor resolvable constructor} if any.
103+
* <p>For registering a bean with a generic type, consider
104+
* {@link #registerBean(String, ParameterizedTypeReference)}.
79105
* @param name the name of the bean
80106
* @param beanClass the class of the bean
81107
*/
82108
<T> void registerBean(String name, Class<T> beanClass);
83109

84110
/**
85-
* Register a bean from the given bean class, customizing it with the customizer
111+
* Register a bean from the given generics-containing type, which
112+
* will be instantiated using the related
113+
* {@link BeanUtils#getResolvableConstructor resolvable constructor} if any.
114+
* @param name the name of the bean
115+
* @param beanType the generics-containing type of the bean
116+
*/
117+
<T> void registerBean(String name, ParameterizedTypeReference<T> beanType);
118+
119+
/**
120+
* Register a bean from the given class, customizing it with the customizer
86121
* callback. The bean will be instantiated using the supplier that can be configured
87122
* in the customizer callback, or will be tentatively instantiated with its
88123
* {@link BeanUtils#getResolvableConstructor resolvable constructor} otherwise.
124+
* <p>For registering a bean with a generic type, consider
125+
* {@link #registerBean(String, ParameterizedTypeReference, Consumer)}.
89126
* @param name the name of the bean
90127
* @param beanClass the class of the bean
91-
* @param customizer callback to customize other bean properties than the name
128+
* @param customizer the callback to customize other bean properties than the name
92129
*/
93130
<T> void registerBean(String name, Class<T> beanClass, Consumer<Spec<T>> customizer);
94131

132+
/**
133+
* Register a bean from the given generics-containing type, customizing it
134+
* with the customizer callback. The bean will be instantiated using the supplier
135+
* that can be configured in the customizer callback, or will be tentatively instantiated
136+
* with its {@link BeanUtils#getResolvableConstructor resolvable constructor} otherwise.
137+
* @param name the name of the bean
138+
* @param beanType the generics-containing type of the bean
139+
* @param customizer the callback to customize other bean properties than the name
140+
*/
141+
<T> void registerBean(String name, ParameterizedTypeReference<T> beanType, Consumer<Spec<T>> customizer);
142+
95143

96144
/**
97145
* Specification for customizing a bean.
@@ -164,20 +212,6 @@ interface Spec<T> {
164212
* @see AbstractBeanDefinition#setInstanceSupplier(Supplier)
165213
*/
166214
Spec<T> supplier(Function<SupplierContext, T> supplier);
167-
168-
/**
169-
* Set a generics-containing target type of this bean.
170-
* @see #targetType(ResolvableType)
171-
* @see RootBeanDefinition#setTargetType(ResolvableType)
172-
*/
173-
Spec<T> targetType(ParameterizedTypeReference<? extends T> type);
174-
175-
/**
176-
* Set a generics-containing target type of this bean.
177-
* @see #targetType(ParameterizedTypeReference)
178-
* @see RootBeanDefinition#setTargetType(ResolvableType)
179-
*/
180-
Spec<T> targetType(ResolvableType type);
181215
}
182216

183217

@@ -188,32 +222,40 @@ interface Spec<T> {
188222
interface SupplierContext {
189223

190224
/**
191-
* Return the bean instance that uniquely matches the given object type, if any.
192-
* @param requiredType type the bean must match; can be an interface or superclass
193-
* @return an instance of the single bean matching the required type
225+
* Return the bean instance that uniquely matches the given type, if any.
226+
* @param beanClass the type the bean must match; can be an interface or superclass
227+
* @return an instance of the single bean matching the bean type
228+
* @see BeanFactory#getBean(String)
229+
*/
230+
<T> T bean(Class<T> beanClass) throws BeansException;
231+
232+
/**
233+
* Return the bean instance that uniquely matches the given generics-containing type, if any.
234+
* @param beanType the generics-containing type the bean must match; can be an interface or superclass
235+
* @return an instance of the single bean matching the bean type
194236
* @see BeanFactory#getBean(String)
195237
*/
196-
<T> T bean(Class<T> requiredType) throws BeansException;
238+
<T> T bean(ParameterizedTypeReference<T> beanType) throws BeansException;
197239

198240
/**
199241
* Return an instance, which may be shared or independent, of the
200242
* specified bean.
201243
* @param name the name of the bean to retrieve
202-
* @param requiredType type the bean must match; can be an interface or superclass
244+
* @param beanClass the type the bean must match; can be an interface or superclass
203245
* @return an instance of the bean.
204246
* @see BeanFactory#getBean(String, Class)
205247
*/
206-
<T> T bean(String name, Class<T> requiredType) throws BeansException;
248+
<T> T bean(String name, Class<T> beanClass) throws BeansException;
207249

208250
/**
209251
* Return a provider for the specified bean, allowing for lazy on-demand retrieval
210252
* of instances, including availability and uniqueness options.
211-
* <p>For matching a generic type, consider {@link #beanProvider(ResolvableType)}.
212-
* @param requiredType type the bean must match; can be an interface or superclass
253+
* <p>For matching a generic type, consider {@link #beanProvider(ParameterizedTypeReference)}.
254+
* @param beanClass the type the bean must match; can be an interface or superclass
213255
* @return a corresponding provider handle
214256
* @see BeanFactory#getBeanProvider(Class)
215257
*/
216-
<T> ObjectProvider<T> beanProvider(Class<T> requiredType);
258+
<T> ObjectProvider<T> beanProvider(Class<T> beanClass);
217259

218260
/**
219261
* Return a provider for the specified bean, allowing for lazy on-demand retrieval
@@ -229,11 +271,11 @@ interface SupplierContext {
229271
* Java compiler warning), consider calling {@link #beanProvider(Class)} with the
230272
* raw type as a second step if no full generic match is
231273
* {@link ObjectProvider#getIfAvailable() available} with this variant.
232-
* @param requiredType type the bean must match; can be a generic type declaration
274+
* @param beanType the generics-containing type the bean must match; can be an interface or superclass
233275
* @return a corresponding provider handle
234276
* @see BeanFactory#getBeanProvider(ResolvableType)
235277
*/
236-
<T> ObjectProvider<T> beanProvider(ResolvableType requiredType);
278+
<T> ObjectProvider<T> beanProvider(ParameterizedTypeReference<T> beanType);
237279
}
238280

239281
}

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

Lines changed: 62 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.springframework.beans.factory.support;
1818

1919
import java.lang.reflect.Constructor;
20+
import java.util.Objects;
2021
import java.util.function.Consumer;
2122
import java.util.function.Function;
2223

@@ -92,13 +93,30 @@ public <T> String registerBean(Class<T> beanClass) {
9293
return beanName;
9394
}
9495

96+
@Override
97+
public <T> String registerBean(ParameterizedTypeReference<T> beanType) {
98+
ResolvableType resolvableType = ResolvableType.forType(beanType);
99+
String beanName = BeanDefinitionReaderUtils.uniqueBeanName(Objects.requireNonNull(resolvableType.resolve()).getName(), this.beanRegistry);
100+
registerBean(beanName, beanType);
101+
return beanName;
102+
}
103+
95104
@Override
96105
public <T> String registerBean(Class<T> beanClass, Consumer<Spec<T>> customizer) {
97106
String beanName = BeanDefinitionReaderUtils.uniqueBeanName(beanClass.getName(), this.beanRegistry);
98107
registerBean(beanName, beanClass, customizer);
99108
return beanName;
100109
}
101110

111+
@Override
112+
public <T> String registerBean(ParameterizedTypeReference<T> beanType, Consumer<Spec<T>> customizer) {
113+
ResolvableType resolvableType = ResolvableType.forType(beanType);
114+
Class<?> beanClass = Objects.requireNonNull(resolvableType.resolve());
115+
String beanName = BeanDefinitionReaderUtils.uniqueBeanName(beanClass.getName(), this.beanRegistry);
116+
registerBean(beanName, beanType, customizer);
117+
return beanName;
118+
}
119+
102120
@Override
103121
public <T> void registerBean(String name, Class<T> beanClass) {
104122
BeanRegistrarBeanDefinition beanDefinition = new BeanRegistrarBeanDefinition(beanClass, this.beanRegistrarClass);
@@ -111,9 +129,11 @@ public <T> void registerBean(String name, Class<T> beanClass) {
111129
}
112130

113131
@Override
114-
public <T> void registerBean(String name, Class<T> beanClass, Consumer<Spec<T>> spec) {
132+
public <T> void registerBean(String name, ParameterizedTypeReference<T> beanType) {
133+
ResolvableType resolvableType = ResolvableType.forType(beanType);
134+
Class<?> beanClass = Objects.requireNonNull(resolvableType.resolve());
115135
BeanRegistrarBeanDefinition beanDefinition = new BeanRegistrarBeanDefinition(beanClass, this.beanRegistrarClass);
116-
spec.accept(new BeanSpecAdapter<>(beanDefinition, this.beanFactory));
136+
beanDefinition.setTargetType(resolvableType);
117137
if (this.customizers != null && this.customizers.containsKey(name)) {
118138
for (BeanDefinitionCustomizer customizer : this.customizers.get(name)) {
119139
customizer.customize(beanDefinition);
@@ -122,6 +142,33 @@ public <T> void registerBean(String name, Class<T> beanClass, Consumer<Spec<T>>
122142
this.beanRegistry.registerBeanDefinition(name, beanDefinition);
123143
}
124144

145+
@Override
146+
public <T> void registerBean(String name, Class<T> beanClass, Consumer<Spec<T>> customizer) {
147+
BeanRegistrarBeanDefinition beanDefinition = new BeanRegistrarBeanDefinition(beanClass, this.beanRegistrarClass);
148+
customizer.accept(new BeanSpecAdapter<>(beanDefinition, this.beanFactory));
149+
if (this.customizers != null && this.customizers.containsKey(name)) {
150+
for (BeanDefinitionCustomizer registryCustomizer : this.customizers.get(name)) {
151+
registryCustomizer.customize(beanDefinition);
152+
}
153+
}
154+
this.beanRegistry.registerBeanDefinition(name, beanDefinition);
155+
}
156+
157+
@Override
158+
public <T> void registerBean(String name, ParameterizedTypeReference<T> beanType, Consumer<Spec<T>> customizer) {
159+
ResolvableType resolvableType = ResolvableType.forType(beanType);
160+
Class<?> beanClass = Objects.requireNonNull(resolvableType.resolve());
161+
BeanRegistrarBeanDefinition beanDefinition = new BeanRegistrarBeanDefinition(beanClass, this.beanRegistrarClass);
162+
beanDefinition.setTargetType(resolvableType);
163+
customizer.accept(new BeanSpecAdapter<>(beanDefinition, this.beanFactory));
164+
if (this.customizers != null && this.customizers.containsKey(name)) {
165+
for (BeanDefinitionCustomizer registryCustomizer : this.customizers.get(name)) {
166+
registryCustomizer.customize(beanDefinition);
167+
}
168+
}
169+
this.beanRegistry.registerBeanDefinition(name, beanDefinition);
170+
}
171+
125172
@Override
126173
public void register(BeanRegistrar registrar) {
127174
Assert.notNull(registrar, "'registrar' must not be null");
@@ -238,18 +285,6 @@ public Spec<T> supplier(Function<SupplierContext, T> supplier) {
238285
supplier.apply(new SupplierContextAdapter(this.beanFactory)));
239286
return this;
240287
}
241-
242-
@Override
243-
public Spec<T> targetType(ParameterizedTypeReference<? extends T> targetType) {
244-
this.beanDefinition.setTargetType(ResolvableType.forType(targetType));
245-
return this;
246-
}
247-
248-
@Override
249-
public Spec<T> targetType(ResolvableType targetType) {
250-
this.beanDefinition.setTargetType(targetType);
251-
return this;
252-
}
253288
}
254289

255290

@@ -262,23 +297,28 @@ public SupplierContextAdapter(ListableBeanFactory beanFactory) {
262297
}
263298

264299
@Override
265-
public <T> T bean(Class<T> requiredType) throws BeansException {
266-
return this.beanFactory.getBean(requiredType);
300+
public <T> T bean(Class<T> beanClass) throws BeansException {
301+
return this.beanFactory.getBean(beanClass);
302+
}
303+
304+
@Override
305+
public <T> T bean(ParameterizedTypeReference<T> beanType) throws BeansException {
306+
return this.beanFactory.getBeanProvider(beanType).getObject();
267307
}
268308

269309
@Override
270-
public <T> T bean(String name, Class<T> requiredType) throws BeansException {
271-
return this.beanFactory.getBean(name, requiredType);
310+
public <T> T bean(String name, Class<T> beanClass) throws BeansException {
311+
return this.beanFactory.getBean(name, beanClass);
272312
}
273313

274314
@Override
275-
public <T> ObjectProvider<T> beanProvider(Class<T> requiredType) {
276-
return this.beanFactory.getBeanProvider(requiredType);
315+
public <T> ObjectProvider<T> beanProvider(Class<T> beanClass) {
316+
return this.beanFactory.getBeanProvider(beanClass);
277317
}
278318

279319
@Override
280-
public <T> ObjectProvider<T> beanProvider(ResolvableType requiredType) {
281-
return this.beanFactory.getBeanProvider(requiredType);
320+
public <T> ObjectProvider<T> beanProvider(ParameterizedTypeReference<T> beanType) {
321+
return this.beanFactory.getBeanProvider(beanType);
282322
}
283323
}
284324

spring-beans/src/main/kotlin/org/springframework/beans/factory/BeanRegistrarDsl.kt

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -168,12 +168,8 @@ open class BeanRegistrarDsl(private val init: BeanRegistrarDsl.() -> Unit): Bean
168168
if (prototype) {
169169
it.prototype()
170170
}
171-
val resolvableType = ResolvableType.forType(object: ParameterizedTypeReference<T>() {});
172-
if (resolvableType.hasGenerics()) {
173-
it.targetType(resolvableType)
174-
}
175171
}
176-
registry.registerBean(name, T::class.java, customizer)
172+
registry.registerBean(name, object: ParameterizedTypeReference<T>() {}, customizer)
177173
}
178174

179175
/**
@@ -234,12 +230,8 @@ open class BeanRegistrarDsl(private val init: BeanRegistrarDsl.() -> Unit): Bean
234230
if (prototype) {
235231
it.prototype()
236232
}
237-
val resolvableType = ResolvableType.forType(object: ParameterizedTypeReference<T>() {});
238-
if (resolvableType.hasGenerics()) {
239-
it.targetType(resolvableType)
240-
}
241233
}
242-
return registry.registerBean(T::class.java, customizer)
234+
return registry.registerBean(object: ParameterizedTypeReference<T>() {}, customizer)
243235
}
244236

245237
/**
@@ -304,12 +296,8 @@ open class BeanRegistrarDsl(private val init: BeanRegistrarDsl.() -> Unit): Bean
304296
it.supplier {
305297
SupplierContextDsl<T>(it, env).supplier()
306298
}
307-
val resolvableType = ResolvableType.forType(object: ParameterizedTypeReference<T>() {});
308-
if (resolvableType.hasGenerics()) {
309-
it.targetType(resolvableType)
310-
}
311299
}
312-
registry.registerBean(name, T::class.java, customizer)
300+
registry.registerBean(name, object: ParameterizedTypeReference<T>() {}, customizer)
313301
}
314302

315303
inline fun <reified T : Any> registerBean(autowirable: Boolean = true,
@@ -372,12 +360,8 @@ open class BeanRegistrarDsl(private val init: BeanRegistrarDsl.() -> Unit): Bean
372360
it.supplier {
373361
SupplierContextDsl<T>(it, env).supplier()
374362
}
375-
val resolvableType = ResolvableType.forType(object: ParameterizedTypeReference<T>() {});
376-
if (resolvableType.hasGenerics()) {
377-
it.targetType(resolvableType)
378-
}
379363
}
380-
return registry.registerBean(T::class.java, customizer)
364+
return registry.registerBean(object: ParameterizedTypeReference<T>() {}, customizer)
381365
}
382366

383367
// Function with 0 parameter
@@ -1094,7 +1078,7 @@ open class BeanRegistrarDsl(private val init: BeanRegistrarDsl.() -> Unit): Bean
10941078
* @return a corresponding provider handle
10951079
*/
10961080
inline fun <reified T : Any> beanProvider() : ObjectProvider<T> =
1097-
context.beanProvider(ResolvableType.forType((object : ParameterizedTypeReference<T>() {}).type))
1081+
context.beanProvider(object : ParameterizedTypeReference<T>() {})
10981082
}
10991083

11001084
override fun register(registry: BeanRegistry, env: Environment) {

0 commit comments

Comments
 (0)