Skip to content

Commit c0c78bd

Browse files
committed
Rename OverrideMetadata for Bean Overrides
Prior to this commit, OverrideMetadata was the only public type in the org.springframework.test.context.bean.override package whose name did not start with BeanOverride. In addition, an OverrideMetadata component plays multiple roles in addition to serving as a holder for metadata. This commit therefore renames OverrideMetadata to BeanOverrideHandler. In addition, this commit updates the affected documentation and renames the following related methods in the Bean Override support. - BeanOverrideHandler: createOverride() -> createOverrideInstance() - BeanOverrideHandler: track() -> trackOverrideInstance() - BeanOverrideProcessor: createMetadata() -> createHandler() - BeanOverrideContextCustomizer: getMetadata() -> getBeanOverrideHandlers() - BeanOverrideRegistrar: registerNameForMetadata() -> registerBeanOverrideHandler() - BeanOverrideRegistrar: markWrapEarly() -> registerWrappingBeanOverrideHandler() Closes gh-33702
1 parent ab4fe5a commit c0c78bd

28 files changed

+669
-658
lines changed

framework-docs/modules/ROOT/pages/testing/testcontext-framework/bean-overriding.adoc

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ https://site.mockito.org/[Mockito] third-party library.
2222
The three annotations mentioned above build upon the `@BeanOverride` meta-annotation and
2323
associated infrastructure, which allows one to define custom bean overriding variants.
2424

25-
To create custom bean override support, the following is needed:
25+
To implement custom bean override support, the following is needed:
2626

2727
* An annotation meta-annotated with `@BeanOverride` that defines the
2828
`BeanOverrideProcessor` to use
2929
* A custom `BeanOverrideProcessor` implementation
30-
* One or more concrete `OverrideMetadata` implementations provided by the processor
30+
* One or more concrete `BeanOverrideHandler` implementations created by the processor
3131

3232
The Spring TestContext framework includes implementations of the following APIs that
3333
support bean overriding and are responsible for setting up the rest of the infrastructure.
@@ -43,11 +43,11 @@ properties file].
4343

4444
The bean overriding infrastructure searches in test classes for any field meta-annotated
4545
with `@BeanOverride` and instantiates the corresponding `BeanOverrideProcessor` which is
46-
responsible for registering appropriate `OverrideMetadata`.
46+
responsible for creating an appropriate `BeanOverrideHandler`.
4747

48-
The internal `BeanOverrideBeanFactoryPostProcessor` then uses that information to alter
49-
the test's `ApplicationContext` by registering and replacing beans as defined by the
50-
corresponding `BeanOverrideStrategy`:
48+
The internal `BeanOverrideBeanFactoryPostProcessor` then uses bean override handlers to
49+
alter the test's `ApplicationContext` by creating, replacing, or wrapping beans as
50+
defined by the corresponding `BeanOverrideStrategy`:
5151

5252
`REPLACE`::
5353
Replaces the bean. Throws an exception if a corresponding bean does not exist.
@@ -65,11 +65,11 @@ heuristics it can perform to locate a bean. Either the `BeanOverrideProcessor` c
6565
the name of the bean to override, or it can be unambiguously selected given the type of
6666
the annotated field and its qualifying annotations.
6767
68-
Typically, the bean is selected by type by the `BeanOverrideFactoryPostProcessor`.
68+
Typically, the bean is selected "by type" by the `BeanOverrideFactoryPostProcessor`.
6969
Alternatively, the user can directly provide the bean name in the custom annotation.
7070
71-
Some `BeanOverrideProcessor` implementations could also internally compute a bean name
72-
based on a convention or another advanced method.
71+
`BeanOverrideProcessor` implementations may also internally compute a bean name based on
72+
a convention or some other method.
7373
====
7474

7575
NOTE: Only _singleton_ beans can be overridden. Any attempt to override a non-singleton

spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideBeanFactoryPostProcessor.java

Lines changed: 65 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,12 @@
4747
* accordingly.
4848
*
4949
* <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.
5454
*
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
5656
* only prepares the bean factory for the identified, unique set of bean overrides.
5757
*
5858
* @author Simon Baslé
@@ -66,22 +66,23 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
6666

6767
private static final BeanNameGenerator beanNameGenerator = DefaultBeanNameGenerator.INSTANCE;
6868

69-
private final Set<OverrideMetadata> metadata;
69+
private final Set<BeanOverrideHandler> beanOverrideHandlers;
7070

71-
private final BeanOverrideRegistrar overrideRegistrar;
71+
private final BeanOverrideRegistrar beanOverrideRegistrar;
7272

7373

7474
/**
7575
* 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
8180
*/
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;
8586
}
8687

8788

@@ -92,27 +93,27 @@ public int getOrder() {
9293

9394
@Override
9495
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);
9798
}
9899
}
99100

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();
103104
Assert.state(!BeanFactoryUtils.isFactoryDereference(beanName),() -> """
104105
Unable to override bean '%s' for field '%s.%s': a FactoryBean cannot be overridden. \
105106
To override the bean created by the FactoryBean, remove the '&' prefix.""".formatted(
106107
beanName, field.getDeclaringClass().getSimpleName(), field.getName()));
107108

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);
112113
}
113114
}
114115

115-
private void replaceBean(ConfigurableListableBeanFactory beanFactory, OverrideMetadata overrideMetadata,
116+
private void replaceOrCreateBean(ConfigurableListableBeanFactory beanFactory, BeanOverrideHandler handler,
116117
boolean requireExistingBean) {
117118

118119
// NOTE: This method supports 3 distinct scenarios which must be accounted for.
@@ -121,10 +122,10 @@ private void replaceBean(ConfigurableListableBeanFactory beanFactory, OverrideMe
121122
// 2) AOT processing
122123
// 3) AOT runtime
123124

124-
String beanName = overrideMetadata.getBeanName();
125+
String beanName = handler.getBeanName();
125126
BeanDefinition existingBeanDefinition = null;
126127
if (beanName == null) {
127-
beanName = getBeanNameForType(beanFactory, overrideMetadata, requireExistingBean);
128+
beanName = getBeanNameForType(beanFactory, handler, requireExistingBean);
128129
if (beanName != null) {
129130
// We are overriding an existing bean by-type.
130131
beanName = BeanFactoryUtils.transformedBeanName(beanName);
@@ -141,7 +142,7 @@ private void replaceBean(ConfigurableListableBeanFactory beanFactory, OverrideMe
141142
}
142143
}
143144
else {
144-
Set<String> candidates = getExistingBeanNamesByType(beanFactory, overrideMetadata, false);
145+
Set<String> candidates = getExistingBeanNamesByType(beanFactory, handler, false);
145146
if (candidates.contains(beanName)) {
146147
// We are overriding an existing bean by-name.
147148
existingBeanDefinition = beanFactory.getBeanDefinition(beanName);
@@ -150,7 +151,7 @@ else if (requireExistingBean) {
150151
throw new IllegalStateException("""
151152
Unable to override bean: there is no bean to replace \
152153
with name [%s] and type [%s]."""
153-
.formatted(beanName, overrideMetadata.getBeanType()));
154+
.formatted(beanName, handler.getBeanType()));
154155
}
155156
}
156157

@@ -180,7 +181,7 @@ else if (Boolean.getBoolean(AbstractAotProcessor.AOT_PROCESSING)) {
180181
"that doesn't implement BeanDefinitionRegistry: " + beanFactory.getClass().getName());
181182
}
182183

183-
RootBeanDefinition pseudoBeanDefinition = createPseudoBeanDefinition(overrideMetadata);
184+
RootBeanDefinition pseudoBeanDefinition = createPseudoBeanDefinition(handler);
184185

185186
// Generate a name for the nonexistent bean.
186187
if (PSEUDO_BEAN_NAME_PLACEHOLDER.equals(beanName)) {
@@ -190,9 +191,9 @@ else if (Boolean.getBoolean(AbstractAotProcessor.AOT_PROCESSING)) {
190191
registry.registerBeanDefinition(beanName, pseudoBeanDefinition);
191192
}
192193

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);
196197

197198
// Now we have an instance (the override) that we can manually register as a singleton.
198199
//
@@ -202,7 +203,7 @@ else if (Boolean.getBoolean(AbstractAotProcessor.AOT_PROCESSING)) {
202203
//
203204
// As a bonus, by manually registering a singleton during "AOT processing", we allow
204205
// 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 --
206207
// for example, when @MockitoBean creates a mock based on a JDK dynamic proxy.
207208
if (beanFactory.containsSingleton(beanName)) {
208209
destroySingleton(beanFactory, beanName);
@@ -211,73 +212,74 @@ else if (Boolean.getBoolean(AbstractAotProcessor.AOT_PROCESSING)) {
211212
}
212213

213214
/**
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.
216218
* <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}
218220
* phase.
219221
*/
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();
222224
if (beanName == null) {
223-
Set<String> candidateNames = getExistingBeanNamesByType(beanFactory, overrideMetadata, true);
225+
Set<String> candidateNames = getExistingBeanNamesByType(beanFactory, handler, true);
224226
int candidateCount = candidateNames.size();
225227
if (candidateCount != 1) {
226-
Field field = overrideMetadata.getField();
228+
Field field = handler.getField();
227229
throw new IllegalStateException("""
228230
Unable to select a bean to override by wrapping: found %d bean instances of type %s \
229231
(as required by annotated field '%s.%s')%s"""
230-
.formatted(candidateCount, overrideMetadata.getBeanType(),
232+
.formatted(candidateCount, handler.getBeanType(),
231233
field.getDeclaringClass().getSimpleName(), field.getName(),
232234
(candidateCount > 0 ? ": " + candidateNames : "")));
233235
}
234236
beanName = BeanFactoryUtils.transformedBeanName(candidateNames.iterator().next());
235237
}
236238
else {
237-
Set<String> candidates = getExistingBeanNamesByType(beanFactory, overrideMetadata, false);
239+
Set<String> candidates = getExistingBeanNamesByType(beanFactory, handler, false);
238240
if (!candidates.contains(beanName)) {
239241
throw new IllegalStateException("""
240242
Unable to override bean by wrapping: there is no existing bean \
241243
with name [%s] and type [%s]."""
242-
.formatted(beanName, overrideMetadata.getBeanType()));
244+
.formatted(beanName, handler.getBeanType()));
243245
}
244246
}
245247
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);
248250
}
249251

250252
@Nullable
251-
private String getBeanNameForType(ConfigurableListableBeanFactory beanFactory, OverrideMetadata overrideMetadata,
253+
private String getBeanNameForType(ConfigurableListableBeanFactory beanFactory, BeanOverrideHandler handler,
252254
boolean requireExistingBean) {
253255

254-
Set<String> candidateNames = getExistingBeanNamesByType(beanFactory, overrideMetadata, true);
256+
Set<String> candidateNames = getExistingBeanNamesByType(beanFactory, handler, true);
255257
int candidateCount = candidateNames.size();
256258
if (candidateCount == 1) {
257259
return candidateNames.iterator().next();
258260
}
259261
else if (candidateCount == 0) {
260262
if (requireExistingBean) {
261-
Field field = overrideMetadata.getField();
263+
Field field = handler.getField();
262264
throw new IllegalStateException(
263265
"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()));
265267
}
266268
return null;
267269
}
268270

269-
Field field = overrideMetadata.getField();
271+
Field field = handler.getField();
270272
throw new IllegalStateException("""
271273
Unable to select a bean to override: found %s beans of type %s \
272274
(as required by annotated field '%s.%s'): %s"""
273-
.formatted(candidateCount, overrideMetadata.getBeanType(), field.getDeclaringClass().getSimpleName(),
275+
.formatted(candidateCount, handler.getBeanType(), field.getDeclaringClass().getSimpleName(),
274276
field.getName(), candidateNames));
275277
}
276278

277-
private Set<String> getExistingBeanNamesByType(ConfigurableListableBeanFactory beanFactory, OverrideMetadata metadata,
279+
private Set<String> getExistingBeanNamesByType(ConfigurableListableBeanFactory beanFactory, BeanOverrideHandler handler,
278280
boolean checkAutowiredCandidate) {
279281

280-
ResolvableType resolvableType = metadata.getBeanType();
282+
ResolvableType resolvableType = handler.getBeanType();
281283
Class<?> type = resolvableType.toClass();
282284

283285
// Start with matching bean names for type, excluding FactoryBeans.
@@ -296,15 +298,15 @@ private Set<String> getExistingBeanNamesByType(ConfigurableListableBeanFactory b
296298

297299
// Filter out non-matching autowire candidates.
298300
if (checkAutowiredCandidate) {
299-
DependencyDescriptor descriptor = new DependencyDescriptor(metadata.getField(), true);
301+
DependencyDescriptor descriptor = new DependencyDescriptor(handler.getField(), true);
300302
beanNames.removeIf(beanName -> !beanFactory.isAutowireCandidate(beanName, descriptor));
301303
}
302304
// Filter out scoped proxy targets.
303305
beanNames.removeIf(ScopedProxyUtils::isScopedTarget);
304306

305307
// In case of multiple matches, fall back on the field's name as a last resort.
306308
if (beanNames.size() > 1) {
307-
String fieldName = metadata.getField().getName();
309+
String fieldName = handler.getField().getName();
308310
if (beanNames.contains(fieldName)) {
309311
return Set.of(fieldName);
310312
}
@@ -313,21 +315,21 @@ private Set<String> getExistingBeanNamesByType(ConfigurableListableBeanFactory b
313315
}
314316

315317
/**
316-
* Create a pseudo-{@link BeanDefinition} for the supplied {@link OverrideMetadata},
318+
* Create a pseudo-{@link BeanDefinition} for the supplied {@link BeanOverrideHandler},
317319
* whose {@linkplain RootBeanDefinition#getTargetType() target type} and
318320
* {@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},
321323
* respectively.
322324
* <p>The returned bean definition should <strong>not</strong> be used to create
323325
* a bean instance but rather only for the purpose of having suitable bean
324326
* definition metadata available in the {@link BeanFactory} &mdash; for example,
325327
* for autowiring candidate resolution.
326328
*/
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());
331333
return definition;
332334
}
333335

spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideContextCustomizer.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,10 @@ class BeanOverrideContextCustomizer implements ContextCustomizer {
4444
"org.springframework.test.context.bean.override.internalWrapEarlyBeanPostProcessor";
4545

4646

47-
private final Set<OverrideMetadata> metadata;
47+
private final Set<BeanOverrideHandler> handlers;
4848

49-
BeanOverrideContextCustomizer(Set<OverrideMetadata> metadata) {
50-
this.metadata = metadata;
49+
BeanOverrideContextCustomizer(Set<BeanOverrideHandler> handlers) {
50+
this.handlers = handlers;
5151
}
5252

5353
@Override
@@ -58,17 +58,17 @@ public void customizeContext(ConfigurableApplicationContext context, MergedConte
5858
// to register them as manual singleton instances. In addition, registration of
5959
// the BeanOverrideBeanFactoryPostProcessor as a singleton is a requirement for
6060
// AOT processing, since a bean definition cannot be generated for the
61-
// Set<OverrideMetadata> argument that it accepts in its constructor.
61+
// Set<BeanOverrideHandler> argument that it accepts in its constructor.
6262
BeanOverrideRegistrar beanOverrideRegistrar = new BeanOverrideRegistrar(beanFactory);
6363
beanFactory.registerSingleton(REGISTRAR_BEAN_NAME, beanOverrideRegistrar);
6464
beanFactory.registerSingleton(INFRASTRUCTURE_BEAN_NAME,
65-
new BeanOverrideBeanFactoryPostProcessor(this.metadata, beanOverrideRegistrar));
65+
new BeanOverrideBeanFactoryPostProcessor(this.handlers, beanOverrideRegistrar));
6666
beanFactory.registerSingleton(EARLY_INFRASTRUCTURE_BEAN_NAME,
6767
new WrapEarlyBeanPostProcessor(beanOverrideRegistrar));
6868
}
6969

70-
Set<OverrideMetadata> getMetadata() {
71-
return this.metadata;
70+
Set<BeanOverrideHandler> getBeanOverrideHandlers() {
71+
return this.handlers;
7272
}
7373

7474
@Override
@@ -80,12 +80,12 @@ public boolean equals(Object other) {
8080
return false;
8181
}
8282
BeanOverrideContextCustomizer that = (BeanOverrideContextCustomizer) other;
83-
return this.metadata.equals(that.metadata);
83+
return this.handlers.equals(that.handlers);
8484
}
8585

8686
@Override
8787
public int hashCode() {
88-
return this.metadata.hashCode();
88+
return this.handlers.hashCode();
8989
}
9090

9191
}

0 commit comments

Comments
 (0)