Skip to content

Commit 40ca83d

Browse files
committedSep 28, 2024
Revise Bean Override internals and Javadoc
1 parent 56f3a48 commit 40ca83d

19 files changed

+151
-146
lines changed
 

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.test.context.bean.override;
1818

19+
import java.lang.annotation.Documented;
1920
import java.lang.annotation.ElementType;
2021
import java.lang.annotation.Retention;
2122
import java.lang.annotation.RetentionPolicy;
@@ -24,17 +25,23 @@
2425
/**
2526
* Mark a composed annotation as eligible for Bean Override processing.
2627
*
27-
* <p>Specifying this annotation triggers the configured {@link BeanOverrideProcessor}
28+
* <p>Specifying this annotation registers the configured {@link BeanOverrideProcessor}
2829
* which must be capable of handling the composed annotation and its attributes.
2930
*
3031
* <p>Since the composed annotation should only be applied to fields, it is
31-
* expected that it has a {@link Target} of {@link ElementType#FIELD FIELD}.
32+
* expected that it is meta-annotated with {@link Target @Target(ElementType.FIELD)}.
33+
*
34+
* <p>For concrete examples, see
35+
* {@link org.springframework.test.context.bean.override.convention.TestBean @TestBean},
36+
* {@link org.springframework.test.context.bean.override.mockito.MockitoBean @MockitoBean}, and
37+
* {@link org.springframework.test.context.bean.override.mockito.MockitoSpyBean @MockitoSpyBean}.
3238
*
3339
* @author Simon Baslé
3440
* @since 6.2
3541
*/
3642
@Retention(RetentionPolicy.RUNTIME)
3743
@Target(ElementType.ANNOTATION_TYPE)
44+
@Documented
3845
public @interface BeanOverride {
3946

4047
/**

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,12 @@
6363
*/
6464
class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor, Ordered {
6565

66+
private static final BeanNameGenerator beanNameGenerator = DefaultBeanNameGenerator.INSTANCE;
67+
6668
private final Set<OverrideMetadata> metadata;
6769

6870
private final BeanOverrideRegistrar overrideRegistrar;
6971

70-
private final BeanNameGenerator beanNameGenerator = new DefaultBeanNameGenerator();
71-
7272

7373
/**
7474
* Create a new {@code BeanOverrideBeanFactoryPostProcessor} with the supplied
@@ -215,7 +215,7 @@ else if (candidateCount == 0) {
215215
"Unable to override bean: no bean definitions of type %s (as required by annotated field '%s.%s')"
216216
.formatted(overrideMetadata.getBeanType(), field.getDeclaringClass().getSimpleName(), field.getName()));
217217
}
218-
return this.beanNameGenerator.generateBeanName(beanDefinition, registry);
218+
return beanNameGenerator.generateBeanName(beanDefinition, registry);
219219
}
220220

221221
Field field = overrideMetadata.getField();
@@ -230,7 +230,7 @@ private Set<String> getExistingBeanNamesByType(ConfigurableListableBeanFactory b
230230
boolean checkAutowiredCandidate) {
231231

232232
ResolvableType resolvableType = metadata.getBeanType();
233-
Class<?> type = resolvableType.resolve(Object.class);
233+
Class<?> type = resolvableType.toClass();
234234

235235
// Start with matching bean names for type, excluding FactoryBeans.
236236
Set<String> beanNames = new LinkedHashSet<>(

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
* <p>At least one composed annotation that is meta-annotated with
2727
* {@link BeanOverride @BeanOverride} must be a companion of this processor and
2828
* may provide additional user settings that drive how the concrete
29-
* {@link OverrideMetadata} is configured.
29+
* {@code OverrideMetadata} is configured.
3030
*
3131
* <p>Implementations are required to have a no-argument constructor and be
3232
* stateless.
@@ -41,7 +41,7 @@ public interface BeanOverrideProcessor {
4141
/**
4242
* Create an {@link OverrideMetadata} instance for the given annotated field.
4343
* @param overrideAnnotation the composed annotation that declares the
44-
* {@link BeanOverride @BeanOverride} annotation that triggers this processor
44+
* {@link BeanOverride @BeanOverride} annotation which registers this processor
4545
* @param testClass the test class to process
4646
* @param field the annotated field
4747
* @return the {@link OverrideMetadata} instance that should handle the

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,15 @@
2121
*
2222
* @author Simon Baslé
2323
* @author Stephane Nicoll
24+
* @author Sam Brannen
2425
* @since 6.2
2526
*/
2627
public enum BeanOverrideStrategy {
2728

2829
/**
2930
* Replace a given bean definition, immediately preparing a singleton instance.
30-
* <p>Fails if the original bean definition exists. To create a new bean
31-
* definition in such a case, use {@link #REPLACE_OR_CREATE_DEFINITION}.
31+
* <p>Fails if the original bean definition does not exist. To create a new bean
32+
* definition in such a case, use {@link #REPLACE_OR_CREATE_DEFINITION} instead.
3233
*/
3334
REPLACE_DEFINITION,
3435

‎spring-test/src/main/java/org/springframework/test/context/bean/override/convention/TestBean.java

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@
2626
import org.springframework.test.context.bean.override.BeanOverride;
2727

2828
/**
29-
* Mark a field to override a bean definition in the {@code BeanFactory}.
29+
* {@code @TestBean} is an annotation that can be applied to a field in a test
30+
* class to override a bean in the test's
31+
* {@link org.springframework.context.ApplicationContext ApplicationContext}
32+
* using a static factory method.
3033
*
3134
* <p>By default, the bean to override is inferred from the type of the
3235
* annotated field. This requires that exactly one matching bean definition is
@@ -57,13 +60,12 @@
5760
*
5861
* <p>Consider the following example.
5962
*
60-
* <pre><code>
61-
* class CustomerServiceTests {
63+
* <pre><code> class CustomerServiceTests {
6264
*
6365
* &#064;TestBean
6466
* private CustomerRepository repository;
6567
*
66-
* // Tests
68+
* // &#064;Test methods ...
6769
*
6870
* private static CustomerRepository repository() {
6971
* return new TestCustomerRepository();
@@ -79,15 +81,14 @@
7981
* <p>To make things more explicit, the bean and method names can be set,
8082
* as shown in the following example.
8183
*
82-
* <pre><code>
83-
* class CustomerServiceTests {
84+
* <pre><code> class CustomerServiceTests {
8485
*
8586
* &#064;TestBean(name = "customerRepository", methodName = "createTestCustomerRepository")
86-
* private CustomerRepository repository;
87+
* CustomerRepository repository;
8788
*
88-
* // Tests
89+
* // &#064;Test methods ...
8990
*
90-
* private static CustomerRepository createTestCustomerRepository() {
91+
* static CustomerRepository createTestCustomerRepository() {
9192
* return new TestCustomerRepository();
9293
* }
9394
* }</code></pre>
@@ -96,7 +97,8 @@
9697
* @author Stephane Nicoll
9798
* @author Sam Brannen
9899
* @since 6.2
99-
* @see TestBeanOverrideProcessor
100+
* @see org.springframework.test.context.bean.override.mockito.MockitoBean @MockitoBean
101+
* @see org.springframework.test.context.bean.override.mockito.MockitoSpyBean @MockitoSpyBean
100102
*/
101103
@Target(ElementType.FIELD)
102104
@Retention(RetentionPolicy.RUNTIME)
Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import java.lang.reflect.Field;
2020
import java.util.Objects;
2121

22-
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
2322
import org.springframework.beans.factory.config.SingletonBeanRegistry;
2423
import org.springframework.core.ResolvableType;
2524
import org.springframework.core.style.ToStringCreator;
@@ -28,21 +27,21 @@
2827
import org.springframework.test.context.bean.override.OverrideMetadata;
2928

3029
/**
31-
* Base {@link OverrideMetadata} implementation for Mockito.
30+
* Abstract base {@link OverrideMetadata} implementation for Mockito.
3231
*
3332
* @author Phillip Webb
3433
* @author Stephane Nicoll
3534
* @author Sam Brannen
3635
* @since 6.2
3736
*/
38-
abstract class MockitoOverrideMetadata extends OverrideMetadata {
37+
abstract class AbstractMockitoOverrideMetadata extends OverrideMetadata {
3938

4039
private final MockReset reset;
4140

4241
private final boolean proxyTargetAware;
4342

4443

45-
protected MockitoOverrideMetadata(Field field, ResolvableType beanType, @Nullable String beanName,
44+
protected AbstractMockitoOverrideMetadata(Field field, ResolvableType beanType, @Nullable String beanName,
4645
BeanOverrideStrategy strategy, @Nullable MockReset reset, boolean proxyTargetAware) {
4746

4847
super(field, beanType, beanName, strategy);
@@ -69,25 +68,28 @@ boolean isProxyTargetAware() {
6968

7069
@Override
7170
protected void track(Object mock, SingletonBeanRegistry trackingBeanRegistry) {
72-
MockitoBeans tracker = null;
73-
try {
74-
tracker = (MockitoBeans) trackingBeanRegistry.getSingleton(MockitoBeans.class.getName());
75-
}
76-
catch (NoSuchBeanDefinitionException ignored) {
71+
getMockitoBeans(trackingBeanRegistry).add(mock);
72+
}
73+
74+
private static MockitoBeans getMockitoBeans(SingletonBeanRegistry trackingBeanRegistry) {
75+
String beanName = MockitoBeans.class.getName();
76+
MockitoBeans mockitoBeans = null;
77+
if (trackingBeanRegistry.containsSingleton(beanName)) {
78+
mockitoBeans = (MockitoBeans) trackingBeanRegistry.getSingleton(beanName);
7779
}
78-
if (tracker == null) {
79-
tracker = new MockitoBeans();
80-
trackingBeanRegistry.registerSingleton(MockitoBeans.class.getName(), tracker);
80+
if (mockitoBeans == null) {
81+
mockitoBeans = new MockitoBeans();
82+
trackingBeanRegistry.registerSingleton(beanName, mockitoBeans);
8183
}
82-
tracker.add(mock);
84+
return mockitoBeans;
8385
}
8486

8587
@Override
8688
public boolean equals(@Nullable Object other) {
8789
if (other == this) {
8890
return true;
8991
}
90-
return (other instanceof MockitoOverrideMetadata that && super.equals(that) &&
92+
return (other instanceof AbstractMockitoOverrideMetadata that && super.equals(that) &&
9193
(this.reset == that.reset) && (this.proxyTargetAware == that.proxyTargetAware));
9294
}
9395

‎spring-test/src/main/java/org/springframework/test/context/bean/override/mockito/MockReset.java

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616

1717
package org.springframework.test.context.bean.override.mockito;
1818

19-
import java.util.List;
20-
2119
import org.mockito.MockSettings;
2220
import org.mockito.MockingDetails;
2321
import org.mockito.Mockito;
@@ -28,11 +26,15 @@
2826
import org.springframework.util.Assert;
2927

3028
/**
31-
* Reset strategy used on a mock bean. Usually applied to a mock through the
32-
* {@link MockitoBean @MockitoBean} annotation but can also be directly applied
33-
* to any mock in the {@code ApplicationContext} using the static methods.
29+
* Reset strategy used on a mock bean.
30+
*
31+
* <p>Usually applied to a mock via the {@link MockitoBean @MockitoBean} or
32+
* {@link MockitoSpyBean @MockitoSpyBean} annotation but can also be directly
33+
* applied to any mock in the {@code ApplicationContext} using the static methods
34+
* in this class.
3435
*
3536
* @author Phillip Webb
37+
* @author Sam Brannen
3638
* @since 6.2
3739
* @see MockitoResetTestExecutionListener
3840
*/
@@ -49,7 +51,7 @@ public enum MockReset {
4951
AFTER,
5052

5153
/**
52-
* Don't reset the mock.
54+
* Do not reset the mock.
5355
*/
5456
NONE;
5557

@@ -102,39 +104,26 @@ public static MockSettings apply(MockReset reset, MockSettings settings) {
102104
* @return the reset type (never {@code null})
103105
*/
104106
static MockReset get(Object mock) {
105-
MockReset reset = MockReset.NONE;
106107
MockingDetails mockingDetails = Mockito.mockingDetails(mock);
107108
if (mockingDetails.isMock()) {
108109
MockCreationSettings<?> settings = mockingDetails.getMockCreationSettings();
109-
List<InvocationListener> listeners = settings.getInvocationListeners();
110-
for (Object listener : listeners) {
110+
for (InvocationListener listener : settings.getInvocationListeners()) {
111111
if (listener instanceof ResetInvocationListener resetInvocationListener) {
112-
reset = resetInvocationListener.getReset();
112+
return resetInvocationListener.reset;
113113
}
114114
}
115115
}
116-
return reset;
116+
return MockReset.NONE;
117117
}
118118

119119
/**
120120
* Dummy {@link InvocationListener} used to hold the {@link MockReset} value.
121121
*/
122-
private static class ResetInvocationListener implements InvocationListener {
123-
124-
private final MockReset reset;
125-
126-
ResetInvocationListener(MockReset reset) {
127-
this.reset = reset;
128-
}
129-
130-
MockReset getReset() {
131-
return this.reset;
132-
}
122+
private record ResetInvocationListener(MockReset reset) implements InvocationListener {
133123

134124
@Override
135125
public void reportInvocation(MethodInvocationReport methodInvocationReport) {
136126
}
137-
138127
}
139128

140129
}

‎spring-test/src/main/java/org/springframework/test/context/bean/override/mockito/MockitoBean.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,13 @@
2828
import org.springframework.test.context.bean.override.BeanOverride;
2929

3030
/**
31-
* Mark a field to trigger a bean override using a Mockito mock.
31+
* {@code @MockitoBean} is an annotation that can be applied to a field in a test
32+
* class to override a bean in the test's
33+
* {@link org.springframework.context.ApplicationContext ApplicationContext}
34+
* using a Mockito mock.
3235
*
3336
* <p>If no explicit {@link #name()} is specified, a target bean definition is
34-
* selected according to the class of the annotated field, and there must be
37+
* selected according to the type of the annotated field, and there must be
3538
* exactly one such candidate definition in the context. A {@code @Qualifier}
3639
* annotation can be used to help disambiguate.
3740
* If a {@link #name()} is specified, either the definition exists in the
@@ -40,13 +43,14 @@
4043
*
4144
* <p>Dependencies that are known to the application context but are not beans
4245
* (such as those
43-
* {@link org.springframework.beans.factory.config.ConfigurableListableBeanFactory#registerResolvableDependency(Class, Object)
46+
* {@linkplain org.springframework.beans.factory.config.ConfigurableListableBeanFactory#registerResolvableDependency(Class, Object)
4447
* registered directly}) will not be found, and a mocked bean will be added to
4548
* the context alongside the existing dependency.
4649
*
4750
* @author Simon Baslé
4851
* @since 6.2
49-
* @see MockitoSpyBean
52+
* @see org.springframework.test.context.bean.override.mockito.MockitoSpyBean @MockitoSpyBean
53+
* @see org.springframework.test.context.bean.override.convention.TestBean @TestBean
5054
*/
5155
@Target(ElementType.FIELD)
5256
@Retention(RetentionPolicy.RUNTIME)
@@ -63,15 +67,15 @@
6367
String name() default "";
6468

6569
/**
66-
* Extra interfaces that should also be declared on the mock.
70+
* Extra interfaces that should also be declared by the mock.
6771
* <p>Defaults to none.
6872
* @return any extra interfaces
6973
* @see MockSettings#extraInterfaces(Class...)
7074
*/
7175
Class<?>[] extraInterfaces() default {};
7276

7377
/**
74-
* The {@link Answers} type to use on the mock.
78+
* The {@link Answers} type to use in the mock.
7579
* <p>Defaults to {@link Answers#RETURNS_DEFAULTS}.
7680
* @return the answer type
7781
*/

‎spring-test/src/main/java/org/springframework/test/context/bean/override/mockito/MockitoBeanOverrideMetadata.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
* @author Sam Brannen
4646
* @since 6.2
4747
*/
48-
class MockitoBeanOverrideMetadata extends MockitoOverrideMetadata {
48+
class MockitoBeanOverrideMetadata extends AbstractMockitoOverrideMetadata {
4949

5050
private final Set<Class<?>> extraInterfaces;
5151

0 commit comments

Comments
 (0)