Polish reference documentation

This commit is contained in:
Sam Brannen 2024-06-11 16:31:56 +02:00
parent 60b5bbe334
commit f481a4b60b
5 changed files with 83 additions and 84 deletions

View File

@ -167,19 +167,19 @@ therefore recommendable for your parameter names to match the target bean names.
As an alternative for injection by name, consider the JSR-250 `@Resource` annotation As an alternative for injection by name, consider the JSR-250 `@Resource` annotation
which is semantically defined to identify a specific target component by its unique name, which is semantically defined to identify a specific target component by its unique name,
with the declared type being irrelevant for the matching process. `@Autowired` has rather with the declared type being irrelevant for the matching process. `@Autowired` has rather
different semantics: After selecting candidate beans by type, the specified `String` different semantics: after selecting candidate beans by type, the specified `String`
qualifier value is considered within those type-selected candidates only (for example, qualifier value is considered within those type-selected candidates only (for example,
matching an `account` qualifier against beans marked with the same qualifier label). matching an `account` qualifier against beans marked with the same qualifier label).
For beans that are themselves defined as a collection, `Map`, or array type, `@Resource` For beans that are themselves defined as a collection, `Map`, or array type, `@Resource`
is a fine solution, referring to the specific collection or array bean by unique name. is a fine solution, referring to the specific collection or array bean by unique name.
That said, as of 4.3, you can match collection, `Map`, and array types through Spring's That said, you can match collection, `Map`, and array types through Spring's
`@Autowired` type matching algorithm as well, as long as the element type information `@Autowired` type matching algorithm as well, as long as the element type information
is preserved in `@Bean` return type signatures or collection inheritance hierarchies. is preserved in `@Bean` return type signatures or collection inheritance hierarchies.
In this case, you can use qualifier values to select among same-typed collections, In this case, you can use qualifier values to select among same-typed collections,
as outlined in the previous paragraph. as outlined in the previous paragraph.
As of 4.3, `@Autowired` also considers self references for injection (that is, references `@Autowired` also considers self references for injection (that is, references
back to the bean that is currently injected). Note that self injection is a fallback. back to the bean that is currently injected). Note that self injection is a fallback.
Regular dependencies on other components always have precedence. In that sense, self Regular dependencies on other components always have precedence. In that sense, self
references do not participate in regular candidate selection and are therefore in references do not participate in regular candidate selection and are therefore in

View File

@ -78,19 +78,20 @@ lead to concurrent access exceptions, inconsistent state in the bean container,
[[beans-definition-overriding]] [[beans-definition-overriding]]
== Overriding Beans == Overriding Beans
Bean overriding is happening when a bean is registered using an identifier that is Bean overriding occurs when a bean is registered using an identifier that is already
already allocated. While bean overriding is possible, it makes the configuration harder allocated. While bean overriding is possible, it makes the configuration harder to read.
to read and this feature will be deprecated in a future release.
WARNING: Bean overriding will be deprecated in a future release.
To disable bean overriding altogether, you can set the `allowBeanDefinitionOverriding` To disable bean overriding altogether, you can set the `allowBeanDefinitionOverriding`
flag to `false` on the `ApplicationContext` before it is refreshed. In such setup, an flag to `false` on the `ApplicationContext` before it is refreshed. In such a setup, an
exception is thrown if bean overriding is used. exception is thrown if bean overriding is used.
By default, the container logs every bean overriding at `INFO` level so that you can By default, the container logs every attempt to override a bean at `INFO` level so that
adapt your configuration accordingly. While not recommended, you can silence those logs you can adapt your configuration accordingly. While not recommended, you can silence
by setting the `allowBeanDefinitionOverriding` flag to `true`. those logs by setting the `allowBeanDefinitionOverriding` flag to `true`.
.Java-configuration .Java Configuration
**** ****
If you use Java Configuration, a corresponding `@Bean` method always silently overrides If you use Java Configuration, a corresponding `@Bean` method always silently overrides
a scanned bean class with the same component name as long as the return type of the a scanned bean class with the same component name as long as the return type of the
@ -98,8 +99,8 @@ a scanned bean class with the same component name as long as the return type of
the `@Bean` factory method in favor of any pre-declared constructor on the bean class. the `@Bean` factory method in favor of any pre-declared constructor on the bean class.
**** ****
NOTE: We acknowledge that overriding beans in a test scenario is convenient, NOTE: We acknowledge that overriding beans in test scenarios is convenient, and there is
and there is explicit support for this as of Spring Framework 6.2. Please refer to explicit support for this as of Spring Framework 6.2. Please refer to
xref:testing/testcontext-framework/bean-overriding.adoc[this section] for more details. xref:testing/testcontext-framework/bean-overriding.adoc[this section] for more details.

View File

@ -1,24 +1,24 @@
[[spring-testing-annotation-beanoverriding-mockitobean]] [[spring-testing-annotation-beanoverriding-mockitobean]]
= `@MockitoBean` and `@MockitoSpyBean` = `@MockitoBean` and `@MockitoSpyBean`
`@MockitoBean` and `@MockitoSpyBean` are used on test class fields to override beans in `@MockitoBean` and `@MockitoSpyBean` are used on fields in test classes to override beans
the test's `ApplicationContext` with a Mockito mock or spy, respectively. In the latter in the test's `ApplicationContext` with a Mockito mock or spy, respectively. In the
case, the original bean definition is not replaced, but instead an early instance of the latter case, the original bean definition is not replaced, but instead an early instance
bean is captured and wrapped by the spy. of the bean is captured and wrapped by the spy.
By default, the annotated field's type is used to search for candidate definitions to By default, the annotated field's type is used to search for candidate bean definitions
override. If multiple candidates match, the usual `@Qualifier` can be provided to to override. If multiple candidates match, `@Qualifier` can be provided to narrow the
narrow the candidate to override. Alternatively, a candidate whose bean definition name candidate to override. Alternatively, a candidate whose bean definition name matches the
matches the name of the field will match. name of the field will match.
To use a by-name override rather than a by-type override, specify the `name` attribute To use a by-name override rather than a by-type override, specify the `name` attribute
of the annotation. of the annotation.
[WARNING] [WARNING]
==== ====
The qualifiers, including the name of the field are used to determine if a separate Qualifiers, including the name of the field, are used to determine if a separate
`ApplicationContext` needs to be created. If you are using this feature to mock or `ApplicationContext` needs to be created. If you are using this feature to mock or spy
spy the same bean in several tests, make sure to name the field consistently to avoid the same bean in several tests, make sure to name the field consistently to avoid
creating unnecessary contexts. creating unnecessary contexts.
==== ====
@ -26,14 +26,12 @@ Each annotation also defines Mockito-specific attributes to fine-tune the mockin
The `@MockitoBean` annotation uses the `REPLACE_OR_CREATE_DEFINITION` The `@MockitoBean` annotation uses the `REPLACE_OR_CREATE_DEFINITION`
xref:testing/testcontext-framework/bean-overriding.adoc#testcontext-bean-overriding-custom[strategy for test bean overriding]. xref:testing/testcontext-framework/bean-overriding.adoc#testcontext-bean-overriding-custom[strategy for test bean overriding].
If no existing bean definition matches, a new bean definition is created on the fly.
If no definition matches, then a definition is created on-the-fly.
The `@MockitoSpyBean` annotation uses the `WRAP_BEAN` The `@MockitoSpyBean` annotation uses the `WRAP_BEAN`
xref:testing/testcontext-framework/bean-overriding.adoc#testcontext-bean-overriding-custom[strategy], xref:testing/testcontext-framework/bean-overriding.adoc#testcontext-bean-overriding-custom[strategy],
and the original instance is wrapped in a Mockito spy. and the original instance is wrapped in a Mockito spy. This strategy requires that
exactly one candidate bean definition exists.
It requires that exactly one candidate definition exists.
The following example shows how to use the default behavior of the `@MockitoBean` annotation: The following example shows how to use the default behavior of the `@MockitoBean` annotation:
@ -45,7 +43,7 @@ Java::
---- ----
class OverrideBeanTests { class OverrideBeanTests {
@MockitoBean // <1> @MockitoBean // <1>
private CustomService customService; CustomService customService;
// test case body... // test case body...
} }
@ -53,11 +51,11 @@ Java::
<1> Replace the bean with type `CustomService` with a Mockito `mock`. <1> Replace the bean with type `CustomService` with a Mockito `mock`.
====== ======
In the example above, we are creating a mock for `CustomService`. If more that In the example above, we are creating a mock for `CustomService`. If more than one bean
one bean with such type exist, the bean named `customService` is considered. Otherwise, of that type exists, the bean named `customService` is considered. Otherwise, the test
the test will fail and you will need to provide a qualifier of some sort to identify which will fail, and you will need to provide a qualifier of some sort to identify which of the
of the `CustomService` beans you want to override. If no such bean exists, a bean `CustomService` beans you want to override. If no such bean exists, a bean definition
definition will be created with an auto-generated bean name. will be created with an auto-generated bean name.
The following example uses a by-name lookup, rather than a by-type lookup: The following example uses a by-name lookup, rather than a by-type lookup:
@ -69,7 +67,7 @@ Java::
---- ----
class OverrideBeanTests { class OverrideBeanTests {
@MockitoBean(name = "service") // <1> @MockitoBean(name = "service") // <1>
private CustomService customService; CustomService customService;
// test case body... // test case body...
@ -90,7 +88,7 @@ Java::
---- ----
class OverrideBeanTests { class OverrideBeanTests {
@MockitoSpyBean // <1> @MockitoSpyBean // <1>
private CustomService customService; CustomService customService;
// test case body... // test case body...
} }
@ -98,10 +96,10 @@ Java::
<1> Wrap the bean with type `CustomService` with a Mockito `spy`. <1> Wrap the bean with type `CustomService` with a Mockito `spy`.
====== ======
In the example above, we are wrapping the bean with type `CustomService`. If more that In the example above, we are wrapping the bean with type `CustomService`. If more than
one bean with such type exist, the bean named `customService` is considered. Otherwise, one bean of that type exists, the bean named `customService` is considered. Otherwise,
the test will fail and you will need to provide a qualifier of some sort to identify which the test will fail, and you will need to provide a qualifier of some sort to identify
of the `CustomService` beans you want to spy. which of the `CustomService` beans you want to spy.
The following example uses a by-name lookup, rather than a by-type lookup: The following example uses a by-name lookup, rather than a by-type lookup:
@ -113,7 +111,7 @@ Java::
---- ----
class OverrideBeanTests { class OverrideBeanTests {
@MockitoSpyBean(name = "service") // <1> @MockitoSpyBean(name = "service") // <1>
private CustomService customService; CustomService customService;
// test case body... // test case body...

View File

@ -1,30 +1,29 @@
[[spring-testing-annotation-beanoverriding-testbean]] [[spring-testing-annotation-beanoverriding-testbean]]
= `@TestBean` = `@TestBean`
`@TestBean` is used on a test class field to override a specific bean in the test's `@TestBean` is used on a field in a test class to override a specific bean in the test's
`ApplicationContext` with an instance provided by a conventionally named static factory `ApplicationContext` with an instance provided by a factory method.
method.
The associated factory method name is derived from the annotated field's name, or bean The associated factory method name is derived from the annotated field's name, or the
name if specified. A `static` method with no argument that returns a type compatible bean name if specified. The factory method must be `static`, accept no arguments, and
with the type of the bean to override is expected. To make things more explicit, or if have a return type compatible with the type of the bean to override. To make things more
you'd rather use a different name, the annotation allows for a specific method name to explicit, or if you'd rather use a different name, the annotation allows for a specific
be provided. method name to be provided.
By default, the annotated field's type is used to search for candidate definitions to By default, the annotated field's type is used to search for candidate bean definitions
override. If multiple candidates match, the usual `@Qualifier` can be provided to to override. If multiple candidates match, `@Qualifier` can be provided to narrow the
narrow the candidate to override. Alternatively, a candidate whose bean definition name candidate to override. Alternatively, a candidate whose bean definition name matches the
matches the name of the field will match. name of the field will match.
To use a by-name override rather than a by-type override, specify the `name` attribute To use a by-name override rather than a by-type override, specify the `name` attribute
of the annotation. of the annotation.
[WARNING] [WARNING]
==== ====
The qualifiers, including the name of the field are used to determine if a separate Qualifiers, including the name of the field, are used to determine if a separate
`ApplicationContext` needs to be created. If you are using this feature to override `ApplicationContext` needs to be created. If you are using this feature to override the
the same bean in several tests, make sure to name the field consistently to avoid same bean in several tests, make sure to name the field consistently to avoid creating
creating unnecessary contexts. unnecessary contexts.
==== ====
The following example shows how to use the default behavior of the `@TestBean` annotation: The following example shows how to use the default behavior of the `@TestBean` annotation:
@ -37,24 +36,23 @@ Java::
---- ----
class OverrideBeanTests { class OverrideBeanTests {
@TestBean // <1> @TestBean // <1>
private CustomService customService; CustomService customService;
// test case body... // test case body...
private static CustomService customService() { // <2> static CustomService customService() { // <2>
return new MyFakeCustomService(); return new MyFakeCustomService();
} }
} }
---- ----
<1> Mark a field for overriding of the bean with type `CustomService`. <1> Mark a field for overriding the bean with type `CustomService`.
<2> The result of this static method will be used as the instance and injected into the field. <2> The result of this static method will be used as the instance and injected into the field.
====== ======
In the example above, we are overriding the bean with type `CustomService`. If more that In the example above, we are overriding the bean with type `CustomService`. If more than
one bean with such type exist, the bean named `customService` is considered. Otherwise, one bean of that type exists, the bean named `customService` is considered. Otherwise,
the test will fail and you will need to provide a qualifier of some sort to identify which the test will fail, and you will need to provide a qualifier of some sort to identify
of the `CustomService` beans you want to override. which of the `CustomService` beans you want to override.
The following example uses a by-name lookup, rather than a by-type lookup: The following example uses a by-name lookup, rather than a by-type lookup:
@ -66,16 +64,17 @@ Java::
---- ----
class OverrideBeanTests { class OverrideBeanTests {
@TestBean(name = "service", methodName = "createCustomService") // <1> @TestBean(name = "service", methodName = "createCustomService") // <1>
private CustomService customService; CustomService customService;
// test case body... // test case body...
private static CustomService createCustomService() { // <2> static CustomService createCustomService() { // <2>
return new MyFakeCustomService(); return new MyFakeCustomService();
} }
} }
---- ----
<1> Mark a field for overriding of the bean with name `service`. <1> Mark a field for overriding the bean with name `service`, and specify that the
factory method is named `createCustomService`.
<2> The result of this static method will be used as the instance and injected into the field. <2> The result of this static method will be used as the instance and injected into the field.
====== ======

View File

@ -74,14 +74,15 @@ public abstract class OverrideMetadata {
} }
/** /**
* Parse the given {@code testClass} and provide the use of bean override. * Parse the given {@code testClass} and build the corresponding list of
* bean {@code OverrideMetadata}.
* @param testClass the class to parse * @param testClass the class to parse
* @return a list of bean overrides metadata * @return a list of {@code OverrideMetadata}
*/ */
public static List<OverrideMetadata> forTestClass(Class<?> testClass) { public static List<OverrideMetadata> forTestClass(Class<?> testClass) {
List<OverrideMetadata> all = new LinkedList<>(); List<OverrideMetadata> metadataList = new LinkedList<>();
ReflectionUtils.doWithFields(testClass, field -> parseField(field, testClass, all)); ReflectionUtils.doWithFields(testClass, field -> parseField(field, testClass, metadataList));
return all; return metadataList;
} }
private static void parseField(Field field, Class<?> testClass, List<OverrideMetadata> metadataList) { private static void parseField(Field field, Class<?> testClass, List<OverrideMetadata> metadataList) {
@ -182,9 +183,9 @@ public abstract class OverrideMetadata {
@Override @Override
public int hashCode() { public int hashCode() {
int hash = Objects.hash(getClass().hashCode(), this.beanType.getType(), this.beanName, this.strategy); int hash = Objects.hash(getClass(), this.beanType.getType(), this.beanName, this.strategy);
return (this.beanName != null ? hash : hash + return (this.beanName != null ? hash : hash +
Objects.hash(this.field.getName(), Arrays.hashCode(this.field.getAnnotations()))); 31 * Objects.hash(this.field.getName(), Arrays.hashCode(this.field.getAnnotations())));
} }
@Override @Override