47
47
* accordingly.
48
48
*
49
49
* <p>For each override, the bean factory is prepared according to the chosen
50
- * {@linkplain BeanOverrideStrategy override strategy}. The override value is created,
51
- * if necessary, and the necessary infrastructure is updated to allow the value
52
- * to be injected in the corresponding {@linkplain OverrideMetadata#getField() field}
53
- * of the test class.
50
+ * {@linkplain BeanOverrideStrategy override strategy}. The bean override instance
51
+ * is created, if necessary, and the related infrastructure is updated to allow
52
+ * the bean override instance to be injected into the corresponding
53
+ * {@linkplain BeanOverrideHandler#getField() field} of the test class.
54
54
*
55
- * <p>This processor does not work against a particular test class, but rather
55
+ * <p>This processor does not work against a particular test class but rather
56
56
* only prepares the bean factory for the identified, unique set of bean overrides.
57
57
*
58
58
* @author Simon Baslé
@@ -66,22 +66,23 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
66
66
67
67
private static final BeanNameGenerator beanNameGenerator = DefaultBeanNameGenerator .INSTANCE ;
68
68
69
- private final Set <OverrideMetadata > metadata ;
69
+ private final Set <BeanOverrideHandler > beanOverrideHandlers ;
70
70
71
- private final BeanOverrideRegistrar overrideRegistrar ;
71
+ private final BeanOverrideRegistrar beanOverrideRegistrar ;
72
72
73
73
74
74
/**
75
75
* Create a new {@code BeanOverrideBeanFactoryPostProcessor} with the supplied
76
- * set of {@link OverrideMetadata} to process, using the given
77
- * {@link BeanOverrideRegistrar}.
78
- * @param metadata the {@link OverrideMetadata} instances to process
79
- * @param overrideRegistrar the {@code BeanOverrideRegistrar} used to track
80
- * metadata
76
+ * set of {@link BeanOverrideHandler BeanOverrideHandlers} to process, using
77
+ * the given {@link BeanOverrideRegistrar}.
78
+ * @param beanOverrideHandlers the bean override handlers to process
79
+ * @param beanOverrideRegistrar the registrar used to track bean override handlers
81
80
*/
82
- BeanOverrideBeanFactoryPostProcessor (Set <OverrideMetadata > metadata , BeanOverrideRegistrar overrideRegistrar ) {
83
- this .metadata = metadata ;
84
- this .overrideRegistrar = overrideRegistrar ;
81
+ BeanOverrideBeanFactoryPostProcessor (Set <BeanOverrideHandler > beanOverrideHandlers ,
82
+ BeanOverrideRegistrar beanOverrideRegistrar ) {
83
+
84
+ this .beanOverrideHandlers = beanOverrideHandlers ;
85
+ this .beanOverrideRegistrar = beanOverrideRegistrar ;
85
86
}
86
87
87
88
@@ -92,27 +93,27 @@ public int getOrder() {
92
93
93
94
@ Override
94
95
public void postProcessBeanFactory (ConfigurableListableBeanFactory beanFactory ) throws BeansException {
95
- for (OverrideMetadata metadata : this .metadata ) {
96
- registerBeanOverride (beanFactory , metadata );
96
+ for (BeanOverrideHandler handler : this .beanOverrideHandlers ) {
97
+ registerBeanOverride (beanFactory , handler );
97
98
}
98
99
}
99
100
100
- private void registerBeanOverride (ConfigurableListableBeanFactory beanFactory , OverrideMetadata overrideMetadata ) {
101
- String beanName = overrideMetadata .getBeanName ();
102
- Field field = overrideMetadata .getField ();
101
+ private void registerBeanOverride (ConfigurableListableBeanFactory beanFactory , BeanOverrideHandler handler ) {
102
+ String beanName = handler .getBeanName ();
103
+ Field field = handler .getField ();
103
104
Assert .state (!BeanFactoryUtils .isFactoryDereference (beanName ),() -> """
104
105
Unable to override bean '%s' for field '%s.%s': a FactoryBean cannot be overridden. \
105
106
To override the bean created by the FactoryBean, remove the '&' prefix.""" .formatted (
106
107
beanName , field .getDeclaringClass ().getSimpleName (), field .getName ()));
107
108
108
- switch (overrideMetadata .getStrategy ()) {
109
- case REPLACE -> replaceBean (beanFactory , overrideMetadata , true );
110
- case REPLACE_OR_CREATE -> replaceBean (beanFactory , overrideMetadata , false );
111
- case WRAP -> wrapBean (beanFactory , overrideMetadata );
109
+ switch (handler .getStrategy ()) {
110
+ case REPLACE -> replaceOrCreateBean (beanFactory , handler , true );
111
+ case REPLACE_OR_CREATE -> replaceOrCreateBean (beanFactory , handler , false );
112
+ case WRAP -> wrapBean (beanFactory , handler );
112
113
}
113
114
}
114
115
115
- private void replaceBean (ConfigurableListableBeanFactory beanFactory , OverrideMetadata overrideMetadata ,
116
+ private void replaceOrCreateBean (ConfigurableListableBeanFactory beanFactory , BeanOverrideHandler handler ,
116
117
boolean requireExistingBean ) {
117
118
118
119
// NOTE: This method supports 3 distinct scenarios which must be accounted for.
@@ -121,10 +122,10 @@ private void replaceBean(ConfigurableListableBeanFactory beanFactory, OverrideMe
121
122
// 2) AOT processing
122
123
// 3) AOT runtime
123
124
124
- String beanName = overrideMetadata .getBeanName ();
125
+ String beanName = handler .getBeanName ();
125
126
BeanDefinition existingBeanDefinition = null ;
126
127
if (beanName == null ) {
127
- beanName = getBeanNameForType (beanFactory , overrideMetadata , requireExistingBean );
128
+ beanName = getBeanNameForType (beanFactory , handler , requireExistingBean );
128
129
if (beanName != null ) {
129
130
// We are overriding an existing bean by-type.
130
131
beanName = BeanFactoryUtils .transformedBeanName (beanName );
@@ -141,7 +142,7 @@ private void replaceBean(ConfigurableListableBeanFactory beanFactory, OverrideMe
141
142
}
142
143
}
143
144
else {
144
- Set <String > candidates = getExistingBeanNamesByType (beanFactory , overrideMetadata , false );
145
+ Set <String > candidates = getExistingBeanNamesByType (beanFactory , handler , false );
145
146
if (candidates .contains (beanName )) {
146
147
// We are overriding an existing bean by-name.
147
148
existingBeanDefinition = beanFactory .getBeanDefinition (beanName );
@@ -150,7 +151,7 @@ else if (requireExistingBean) {
150
151
throw new IllegalStateException ("""
151
152
Unable to override bean: there is no bean to replace \
152
153
with name [%s] and type [%s]."""
153
- .formatted (beanName , overrideMetadata .getBeanType ()));
154
+ .formatted (beanName , handler .getBeanType ()));
154
155
}
155
156
}
156
157
@@ -180,7 +181,7 @@ else if (Boolean.getBoolean(AbstractAotProcessor.AOT_PROCESSING)) {
180
181
"that doesn't implement BeanDefinitionRegistry: " + beanFactory .getClass ().getName ());
181
182
}
182
183
183
- RootBeanDefinition pseudoBeanDefinition = createPseudoBeanDefinition (overrideMetadata );
184
+ RootBeanDefinition pseudoBeanDefinition = createPseudoBeanDefinition (handler );
184
185
185
186
// Generate a name for the nonexistent bean.
186
187
if (PSEUDO_BEAN_NAME_PLACEHOLDER .equals (beanName )) {
@@ -190,9 +191,9 @@ else if (Boolean.getBoolean(AbstractAotProcessor.AOT_PROCESSING)) {
190
191
registry .registerBeanDefinition (beanName , pseudoBeanDefinition );
191
192
}
192
193
193
- Object override = overrideMetadata . createOverride (beanName , existingBeanDefinition , null );
194
- overrideMetadata . track (override , beanFactory );
195
- this .overrideRegistrar . registerNameForMetadata ( overrideMetadata , beanName );
194
+ Object override = handler . createOverrideInstance (beanName , existingBeanDefinition , null );
195
+ handler . trackOverrideInstance (override , beanFactory );
196
+ this .beanOverrideRegistrar . registerBeanOverrideHandler ( handler , beanName );
196
197
197
198
// Now we have an instance (the override) that we can manually register as a singleton.
198
199
//
@@ -202,7 +203,7 @@ else if (Boolean.getBoolean(AbstractAotProcessor.AOT_PROCESSING)) {
202
203
//
203
204
// As a bonus, by manually registering a singleton during "AOT processing", we allow
204
205
// GenericApplicationContext's preDetermineBeanType() method to transparently register
205
- // runtime hints for a proxy generated by the above createOverride () invocation --
206
+ // runtime hints for a proxy generated by the above createOverrideInstance () invocation --
206
207
// for example, when @MockitoBean creates a mock based on a JDK dynamic proxy.
207
208
if (beanFactory .containsSingleton (beanName )) {
208
209
destroySingleton (beanFactory , beanName );
@@ -211,73 +212,74 @@ else if (Boolean.getBoolean(AbstractAotProcessor.AOT_PROCESSING)) {
211
212
}
212
213
213
214
/**
214
- * Check that the expected bean name is registered and matches the type to override.
215
- * <p>If so, put the override metadata in the early tracking map.
215
+ * Check that a bean with the specified {@link BeanOverrideHandler#getBeanName() name}
216
+ * and {@link BeanOverrideHandler#getBeanType() type} is registered.
217
+ * <p>If so, put the {@link BeanOverrideHandler} in the early tracking map.
216
218
* <p>The map will later be checked to see if a given bean should be wrapped
217
- * upon creation, during the {@link WrapEarlyBeanPostProcessor#getEarlyBeanReference(Object, String) }
219
+ * upon creation, during the {@link WrapEarlyBeanPostProcessor#getEarlyBeanReference}
218
220
* phase.
219
221
*/
220
- private void wrapBean (ConfigurableListableBeanFactory beanFactory , OverrideMetadata overrideMetadata ) {
221
- String beanName = overrideMetadata .getBeanName ();
222
+ private void wrapBean (ConfigurableListableBeanFactory beanFactory , BeanOverrideHandler handler ) {
223
+ String beanName = handler .getBeanName ();
222
224
if (beanName == null ) {
223
- Set <String > candidateNames = getExistingBeanNamesByType (beanFactory , overrideMetadata , true );
225
+ Set <String > candidateNames = getExistingBeanNamesByType (beanFactory , handler , true );
224
226
int candidateCount = candidateNames .size ();
225
227
if (candidateCount != 1 ) {
226
- Field field = overrideMetadata .getField ();
228
+ Field field = handler .getField ();
227
229
throw new IllegalStateException ("""
228
230
Unable to select a bean to override by wrapping: found %d bean instances of type %s \
229
231
(as required by annotated field '%s.%s')%s"""
230
- .formatted (candidateCount , overrideMetadata .getBeanType (),
232
+ .formatted (candidateCount , handler .getBeanType (),
231
233
field .getDeclaringClass ().getSimpleName (), field .getName (),
232
234
(candidateCount > 0 ? ": " + candidateNames : "" )));
233
235
}
234
236
beanName = BeanFactoryUtils .transformedBeanName (candidateNames .iterator ().next ());
235
237
}
236
238
else {
237
- Set <String > candidates = getExistingBeanNamesByType (beanFactory , overrideMetadata , false );
239
+ Set <String > candidates = getExistingBeanNamesByType (beanFactory , handler , false );
238
240
if (!candidates .contains (beanName )) {
239
241
throw new IllegalStateException ("""
240
242
Unable to override bean by wrapping: there is no existing bean \
241
243
with name [%s] and type [%s]."""
242
- .formatted (beanName , overrideMetadata .getBeanType ()));
244
+ .formatted (beanName , handler .getBeanType ()));
243
245
}
244
246
}
245
247
validateBeanDefinition (beanFactory , beanName );
246
- this .overrideRegistrar . markWrapEarly ( overrideMetadata , beanName );
247
- this .overrideRegistrar . registerNameForMetadata ( overrideMetadata , beanName );
248
+ this .beanOverrideRegistrar . registerWrappingBeanOverrideHandler ( handler , beanName );
249
+ this .beanOverrideRegistrar . registerBeanOverrideHandler ( handler , beanName );
248
250
}
249
251
250
252
@ Nullable
251
- private String getBeanNameForType (ConfigurableListableBeanFactory beanFactory , OverrideMetadata overrideMetadata ,
253
+ private String getBeanNameForType (ConfigurableListableBeanFactory beanFactory , BeanOverrideHandler handler ,
252
254
boolean requireExistingBean ) {
253
255
254
- Set <String > candidateNames = getExistingBeanNamesByType (beanFactory , overrideMetadata , true );
256
+ Set <String > candidateNames = getExistingBeanNamesByType (beanFactory , handler , true );
255
257
int candidateCount = candidateNames .size ();
256
258
if (candidateCount == 1 ) {
257
259
return candidateNames .iterator ().next ();
258
260
}
259
261
else if (candidateCount == 0 ) {
260
262
if (requireExistingBean ) {
261
- Field field = overrideMetadata .getField ();
263
+ Field field = handler .getField ();
262
264
throw new IllegalStateException (
263
265
"Unable to override bean: no beans of type %s (as required by annotated field '%s.%s')"
264
- .formatted (overrideMetadata .getBeanType (), field .getDeclaringClass ().getSimpleName (), field .getName ()));
266
+ .formatted (handler .getBeanType (), field .getDeclaringClass ().getSimpleName (), field .getName ()));
265
267
}
266
268
return null ;
267
269
}
268
270
269
- Field field = overrideMetadata .getField ();
271
+ Field field = handler .getField ();
270
272
throw new IllegalStateException ("""
271
273
Unable to select a bean to override: found %s beans of type %s \
272
274
(as required by annotated field '%s.%s'): %s"""
273
- .formatted (candidateCount , overrideMetadata .getBeanType (), field .getDeclaringClass ().getSimpleName (),
275
+ .formatted (candidateCount , handler .getBeanType (), field .getDeclaringClass ().getSimpleName (),
274
276
field .getName (), candidateNames ));
275
277
}
276
278
277
- private Set <String > getExistingBeanNamesByType (ConfigurableListableBeanFactory beanFactory , OverrideMetadata metadata ,
279
+ private Set <String > getExistingBeanNamesByType (ConfigurableListableBeanFactory beanFactory , BeanOverrideHandler handler ,
278
280
boolean checkAutowiredCandidate ) {
279
281
280
- ResolvableType resolvableType = metadata .getBeanType ();
282
+ ResolvableType resolvableType = handler .getBeanType ();
281
283
Class <?> type = resolvableType .toClass ();
282
284
283
285
// Start with matching bean names for type, excluding FactoryBeans.
@@ -296,15 +298,15 @@ private Set<String> getExistingBeanNamesByType(ConfigurableListableBeanFactory b
296
298
297
299
// Filter out non-matching autowire candidates.
298
300
if (checkAutowiredCandidate ) {
299
- DependencyDescriptor descriptor = new DependencyDescriptor (metadata .getField (), true );
301
+ DependencyDescriptor descriptor = new DependencyDescriptor (handler .getField (), true );
300
302
beanNames .removeIf (beanName -> !beanFactory .isAutowireCandidate (beanName , descriptor ));
301
303
}
302
304
// Filter out scoped proxy targets.
303
305
beanNames .removeIf (ScopedProxyUtils ::isScopedTarget );
304
306
305
307
// In case of multiple matches, fall back on the field's name as a last resort.
306
308
if (beanNames .size () > 1 ) {
307
- String fieldName = metadata .getField ().getName ();
309
+ String fieldName = handler .getField ().getName ();
308
310
if (beanNames .contains (fieldName )) {
309
311
return Set .of (fieldName );
310
312
}
@@ -313,21 +315,21 @@ private Set<String> getExistingBeanNamesByType(ConfigurableListableBeanFactory b
313
315
}
314
316
315
317
/**
316
- * Create a pseudo-{@link BeanDefinition} for the supplied {@link OverrideMetadata },
318
+ * Create a pseudo-{@link BeanDefinition} for the supplied {@link BeanOverrideHandler },
317
319
* whose {@linkplain RootBeanDefinition#getTargetType() target type} and
318
320
* {@linkplain RootBeanDefinition#getQualifiedElement() qualified element} are
319
- * the {@linkplain OverrideMetadata #getBeanType() bean type} and
320
- * the {@linkplain OverrideMetadata #getField() field} of the {@code OverrideMetadata },
321
+ * the {@linkplain BeanOverrideHandler #getBeanType() bean type} and
322
+ * the {@linkplain BeanOverrideHandler #getField() field} of the {@code BeanOverrideHandler },
321
323
* respectively.
322
324
* <p>The returned bean definition should <strong>not</strong> be used to create
323
325
* a bean instance but rather only for the purpose of having suitable bean
324
326
* definition metadata available in the {@link BeanFactory} — for example,
325
327
* for autowiring candidate resolution.
326
328
*/
327
- private static RootBeanDefinition createPseudoBeanDefinition (OverrideMetadata metadata ) {
328
- RootBeanDefinition definition = new RootBeanDefinition (metadata .getBeanType ().resolve ());
329
- definition .setTargetType (metadata .getBeanType ());
330
- definition .setQualifiedElement (metadata .getField ());
329
+ private static RootBeanDefinition createPseudoBeanDefinition (BeanOverrideHandler handler ) {
330
+ RootBeanDefinition definition = new RootBeanDefinition (handler .getBeanType ().resolve ());
331
+ definition .setTargetType (handler .getBeanType ());
332
+ definition .setQualifiedElement (handler .getField ());
331
333
return definition ;
332
334
}
333
335
0 commit comments