diff --git a/framework-docs/modules/ROOT/pages/core/beans/annotation-config/autowired-qualifiers.adoc b/framework-docs/modules/ROOT/pages/core/beans/annotation-config/autowired-qualifiers.adoc index 63a67d9fe06d..eb7b1199d07c 100644 --- a/framework-docs/modules/ROOT/pages/core/beans/annotation-config/autowired-qualifiers.adoc +++ b/framework-docs/modules/ROOT/pages/core/beans/annotation-config/autowired-qualifiers.adoc @@ -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 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 -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, 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` 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 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, 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. Regular dependencies on other components always have precedence. In that sense, self references do not participate in regular candidate selection and are therefore in diff --git a/framework-docs/modules/ROOT/pages/core/beans/definition.adoc b/framework-docs/modules/ROOT/pages/core/beans/definition.adoc index 9c46aaec864a..a37dd34abac3 100644 --- a/framework-docs/modules/ROOT/pages/core/beans/definition.adoc +++ b/framework-docs/modules/ROOT/pages/core/beans/definition.adoc @@ -78,19 +78,20 @@ lead to concurrent access exceptions, inconsistent state in the bean container, [[beans-definition-overriding]] == Overriding Beans -Bean overriding is happening when a bean is registered using an identifier that is -already allocated. While bean overriding is possible, it makes the configuration harder -to read and this feature will be deprecated in a future release. +Bean overriding occurs when a bean is registered using an identifier that is already +allocated. While bean overriding is possible, it makes the configuration harder to read. + +WARNING: Bean overriding will be deprecated in a future release. 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. -By default, the container logs every bean overriding at `INFO` level so that you can -adapt your configuration accordingly. While not recommended, you can silence those logs -by setting the `allowBeanDefinitionOverriding` flag to `true`. +By default, the container logs every attempt to override a bean at `INFO` level so that +you can adapt your configuration accordingly. While not recommended, you can silence +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 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. **** -NOTE: We acknowledge that overriding beans in a test scenario is convenient, -and there is explicit support for this as of Spring Framework 6.2. Please refer to +NOTE: We acknowledge that overriding beans in test scenarios is convenient, and there is +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. diff --git a/framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-mockitobean.adoc b/framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-mockitobean.adoc index 85442b628d06..b70f2415bed2 100644 --- a/framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-mockitobean.adoc +++ b/framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-mockitobean.adoc @@ -1,24 +1,24 @@ [[spring-testing-annotation-beanoverriding-mockitobean]] = `@MockitoBean` and `@MockitoSpyBean` -`@MockitoBean` and `@MockitoSpyBean` are used on test class fields to override beans in -the test's `ApplicationContext` with a Mockito mock or spy, respectively. In the latter -case, the original bean definition is not replaced, but instead an early instance of the -bean is captured and wrapped by the spy. +`@MockitoBean` and `@MockitoSpyBean` are used on fields in test classes to override beans +in the test's `ApplicationContext` with a Mockito mock or spy, respectively. In the +latter case, the original bean definition is not replaced, but instead an early instance +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 -override. If multiple candidates match, the usual `@Qualifier` can be provided to -narrow the candidate to override. Alternatively, a candidate whose bean definition name -matches the name of the field will match. +By default, the annotated field's type is used to search for candidate bean definitions +to override. If multiple candidates match, `@Qualifier` can be provided to narrow the +candidate to override. Alternatively, a candidate whose bean definition name matches the +name of the field will match. To use a by-name override rather than a by-type override, specify the `name` attribute of the annotation. [WARNING] ==== -The 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 -spy the same bean in several tests, make sure to name the field consistently to avoid +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 spy +the same bean in several tests, make sure to name the field consistently to avoid 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` xref:testing/testcontext-framework/bean-overriding.adoc#testcontext-bean-overriding-custom[strategy for test bean overriding]. - -If no definition matches, then a definition is created on-the-fly. +If no existing bean definition matches, a new bean definition is created on the fly. The `@MockitoSpyBean` annotation uses the `WRAP_BEAN` xref:testing/testcontext-framework/bean-overriding.adoc#testcontext-bean-overriding-custom[strategy], -and the original instance is wrapped in a Mockito spy. - -It requires that exactly one candidate definition exists. +and the original instance is wrapped in a Mockito spy. This strategy requires that +exactly one candidate bean definition exists. The following example shows how to use the default behavior of the `@MockitoBean` annotation: @@ -44,8 +42,8 @@ Java:: [source,java,indent=0,subs="verbatim,quotes",role="primary"] ---- class OverrideBeanTests { - @MockitoBean // <1> - private CustomService customService; + @MockitoBean // <1> + CustomService customService; // test case body... } @@ -53,11 +51,11 @@ Java:: <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 -one bean with such type exist, 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 -of the `CustomService` beans you want to override. If no such bean exists, a bean -definition will be created with an auto-generated bean name. +In the example above, we are creating a mock for `CustomService`. If more than 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 of the +`CustomService` beans you want to override. If no such bean exists, a bean definition +will be created with an auto-generated bean name. The following example uses a by-name lookup, rather than a by-type lookup: @@ -68,14 +66,14 @@ Java:: [source,java,indent=0,subs="verbatim,quotes",role="primary"] ---- class OverrideBeanTests { - @MockitoBean(name = "service") // <1> - private CustomService customService; + @MockitoBean(name = "service") // <1> + CustomService customService; // test case body... } ---- -<1> Replace the bean named `service` with a Mockito `mock`. +<1> Replace the bean named `service` with a Mockito `mock`. ====== If no bean definition named `service` exists, one is created. @@ -89,8 +87,8 @@ Java:: [source,java,indent=0,subs="verbatim,quotes",role="primary"] ---- class OverrideBeanTests { - @MockitoSpyBean // <1> - private CustomService customService; + @MockitoSpyBean // <1> + CustomService customService; // test case body... } @@ -98,10 +96,10 @@ Java:: <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 -one bean with such type exist, 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 -of the `CustomService` beans you want to spy. +In the example above, we are wrapping the bean with type `CustomService`. If more than +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 of the `CustomService` beans you want to spy. The following example uses a by-name lookup, rather than a by-type lookup: @@ -112,12 +110,12 @@ Java:: [source,java,indent=0,subs="verbatim,quotes",role="primary"] ---- class OverrideBeanTests { - @MockitoSpyBean(name = "service") // <1> - private CustomService customService; + @MockitoSpyBean(name = "service") // <1> + CustomService customService; // test case body... } ---- -<1> Wrap the bean named `service` with a Mockito `spy`. +<1> Wrap the bean named `service` with a Mockito `spy`. ====== diff --git a/framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-testbean.adoc b/framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-testbean.adoc index 7e68e0dec034..8d4ea481aa2e 100644 --- a/framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-testbean.adoc +++ b/framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-testbean.adoc @@ -1,30 +1,29 @@ [[spring-testing-annotation-beanoverriding-testbean]] = `@TestBean` -`@TestBean` is used on a test class field to override a specific bean in the test's -`ApplicationContext` with an instance provided by a conventionally named static factory -method. +`@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 factory method. -The associated factory method name is derived from the annotated field's name, or bean -name if specified. A `static` method with no argument that returns a type compatible -with the type of the bean to override is expected. To make things more explicit, or if -you'd rather use a different name, the annotation allows for a specific method name to -be provided. +The associated factory method name is derived from the annotated field's name, or the +bean name if specified. The factory method must be `static`, accept no arguments, and +have a return type compatible with the type of the bean to override. To make things more +explicit, or if you'd rather use a different name, the annotation allows for a specific +method name to be provided. -By default, the annotated field's type is used to search for candidate definitions to -override. If multiple candidates match, the usual `@Qualifier` can be provided to -narrow the candidate to override. Alternatively, a candidate whose bean definition name -matches the name of the field will match. +By default, the annotated field's type is used to search for candidate bean definitions +to override. If multiple candidates match, `@Qualifier` can be provided to narrow the +candidate to override. Alternatively, a candidate whose bean definition name matches the +name of the field will match. To use a by-name override rather than a by-type override, specify the `name` attribute of the annotation. [WARNING] ==== -The 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 -the same bean in several tests, make sure to name the field consistently to avoid -creating unnecessary contexts. +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 the +same bean in several tests, make sure to name the field consistently to avoid creating +unnecessary contexts. ==== The following example shows how to use the default behavior of the `@TestBean` annotation: @@ -36,25 +35,24 @@ Java:: [source,java,indent=0,subs="verbatim,quotes",role="primary"] ---- class OverrideBeanTests { - @TestBean // <1> - private CustomService customService; + @TestBean // <1> + CustomService customService; // test case body... - private static CustomService customService() { // <2> + static CustomService customService() { // <2> 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. ====== -In the example above, we are overriding the bean with type `CustomService`. If more that -one bean with such type exist, 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 -of the `CustomService` beans you want to override. - +In the example above, we are overriding the bean with type `CustomService`. If more than +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 of the `CustomService` beans you want to override. The following example uses a by-name lookup, rather than a by-type lookup: @@ -65,17 +63,18 @@ Java:: [source,java,indent=0,subs="verbatim,quotes",role="primary"] ---- class OverrideBeanTests { - @TestBean(name = "service", methodName = "createCustomService") // <1> - private CustomService customService; + @TestBean(name = "service", methodName = "createCustomService") // <1> + CustomService customService; // test case body... - private static CustomService createCustomService() { // <2> + static CustomService createCustomService() { // <2> 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. ====== diff --git a/spring-test/src/main/java/org/springframework/test/context/bean/override/OverrideMetadata.java b/spring-test/src/main/java/org/springframework/test/context/bean/override/OverrideMetadata.java index dcda79bcf750..666eba9e7993 100644 --- a/spring-test/src/main/java/org/springframework/test/context/bean/override/OverrideMetadata.java +++ b/spring-test/src/main/java/org/springframework/test/context/bean/override/OverrideMetadata.java @@ -74,14 +74,15 @@ protected OverrideMetadata(Field field, ResolvableType beanType, @Nullable Strin } /** - * 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 - * @return a list of bean overrides metadata + * @return a list of {@code OverrideMetadata} */ public static List forTestClass(Class testClass) { - List all = new LinkedList<>(); - ReflectionUtils.doWithFields(testClass, field -> parseField(field, testClass, all)); - return all; + List metadataList = new LinkedList<>(); + ReflectionUtils.doWithFields(testClass, field -> parseField(field, testClass, metadataList)); + return metadataList; } private static void parseField(Field field, Class testClass, List metadataList) { @@ -182,9 +183,9 @@ public boolean equals(Object other) { @Override 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 + - Objects.hash(this.field.getName(), Arrays.hashCode(this.field.getAnnotations()))); + 31 * Objects.hash(this.field.getName(), Arrays.hashCode(this.field.getAnnotations()))); } @Override