We now invoke the javadoc tool with "--link-modularity-mismatch info"
in order not to fail the build when encountering warnings such as the
following.
> The code being documented uses packages in the unnamed module, but the
> packages defined in https://junit.org/junit5/docs/5.12.2/api/ are in
> named modules.
Closes gh-27497
This commit provides first-class support for Bean Overrides
(@MockitoBean, @MockitoSpyBean, @TestBean, etc.) with
@ContextHierarchy.
Specifically, bean overrides can now specify which ApplicationContext
they target within the context hierarchy by configuring the
`contextName` attribute in the annotation. The `contextName` must match
a corresponding `name` configured via @ContextConfiguration.
For example, the following test class configures the name of the second
hierarchy level to be "child" and simultaneously specifies that the
ExampleService should be wrapped in a Mockito spy in the context named
"child". Consequently, Spring will only attempt to create the spy in
the "child" context and will not attempt to create the spy in the
parent context.
@ExtendWith(SpringExtension.class)
@ContextHierarchy({
@ContextConfiguration(classes = Config1.class),
@ContextConfiguration(classes = Config2.class, name = "child")
})
class MockitoSpyBeanContextHierarchyTests {
@MockitoSpyBean(contextName = "child")
ExampleService service;
// ...
}
See gh-33293
See gh-34597
See gh-34726
Closes gh-34723
Signed-off-by: Sam Brannen <104798+sbrannen@users.noreply.github.com>
For bean override support (@MockitoBean, @TestBean, etc.), the logic
for field injection previously resided in the BeanOverrideRegistry
which resulted in a strange mixture of concerns.
To address that, this commit moves the field injection logic to the
BeanOverrideTestExecutionListener, and the BeanOverrideRegistry now
serves a single role, namely the role of a registry.
Closes gh-34726
Historically, @Configuration classes that did not declare @Bean
methods were allowed to be abstract. However, the changes made in
76a6b9ea79 introduced a regression that prevents such classes from
being abstract, resulting in a BeanInstantiationException. This change
in behavior is caused by the fact that such a @Configuration class is
no longer replaced by a concrete subclass created dynamically by CGLIB.
This commit restores support for abstract @Configuration classes
without @Bean methods by modifying the "no enhancement required" check
in ConfigurationClassParser.
See gh-34486
Closes gh-34663
We have had an ObjectToOptionalConverter since Spring Framework 4.1;
however, prior to this commit we did not have a standard Converter for
the inverse (Optional to Object).
To address that, this commit introduces an OptionalToObjectConverter
that unwraps an Optional, using the ConversionService to convert the
object contained in the Optional (potentially null) to the target type.
This allows for conversions such as the following.
- Optional.empty() -> null
- Optional.of(42) with Integer target -> 42
- Optional.of(42) with String target -> "42"
- Optional.of(42) with Optional<String> target -> Optional.of("42")
The OptionalToObjectConverter is also registered by default in
DefaultConversionService, alongside the existing
ObjectToOptionalConverter.
See gh-20433
Closes gh-34544
Prior to this commit, the Test Bean Override feature provided support
for overriding beans based on qualifier annotations in several
scenarios; however, qualifier annotations got lost if they were
declared on the return type of the @Bean method for the bean being
overridden and the @BeanOverride (such as @MockitoBean) was based on
a supertype of that return type.
To address that, this commit sets the @BeanOverride field as the
"qualified element" in the RootBeanDefinition to ensure that qualifier
annotations are available for subsequent autowiring candidate
resolution.
Closes gh-34646
Now that we are using JDK 18+ (currently JDK 24 -- see JavaConventions
in buildSrc for details), we can reinstate links to JUnit 5 Javadoc APIs.
Closes gh-27497
This commit updates the Javadoc in various places to reflect the fact
that support for convention-based annotation attribute overrides has
been removed.
See gh-28761
Historically, the Spring Framework first had support for repeatable
annotations based on convention and later added explicit support for
Java 8's @Repeatable facility. Consequently, the support for both
types of repeatable annotations has grown a bit intertwined over the
years. However, modern Java applications typically make use of
@Repeatable, and convention-based repeatable annotations have become
more of a niche.
The RepeatableContainers API supports both types of repeatable
annotations with @Repeatable support being the default. However,
RepeatableContainers.of() makes it very easy to enable support for
convention-based repeatable annotations while accidentally disabling
support for @Repeatable, which can lead to subtle bugs – for example,
if convention-based annotations are combined with @Repeatable
annotations. In addition, it is not readily clear how to combine
@Repeatable support with convention-based repeatable annotations.
In light of the above, this commit revises the RepeatableContainers API
to better guide developers to use @Repeatable support for almost all
use cases while still supporting convention-based repeatable
annotations for special use cases.
Specifically:
- RepeatableContainers.of() is now deprecated in favor of the new
RepeatableContainers.explicitRepeatable() method.
- RepeatableContainers.and() is now deprecated in favor of the new
RepeatableContainers.plus() method which declares the repeatable and
container arguments in the same order as the rest of Spring
Framework's repeated annotation APIs.
For example, instead of the following confusing mixture of
repeatable/container and container/repeatable:
RepeatableContainers.of(A.class, A.Container.class)
.and(B.Container.class, B.class)
Developers are now be able to use:
RepeatableContainers.explicitRepeatable(A.class, A.Container.class)
.plus(B.class, B.Container.class)
This commit also overhauls the Javadoc for RepeatableContainers and
explicitly points out that the following is the recommended approach to
support convention-based repeatable annotations while retaining support
for @Repeatable.
RepeatableContainers.standardRepeatables()
.plus(MyRepeatable1.class, MyContainer1.class)
.plus(MyRepeatable2.class, MyContainer2.class)
See gh-20279
Closes gh-34637
This commit extracts AnnotatedElementAdapter from TypeDescriptor and
introduces it as a public, top-level type in the
org.springframework.core.annotation package, and
AnnotatedElementUtils.forAnnotations() now returns an instance of
AnnotatedElementAdapter instead of AnnotatedElementForAnnotations which
has been removed.
In addition, this commit adds missing Javadoc for
AnnotatedElementAdapter and refines some of the implementation.
Closes gh-34628
This commit removes the BDDMockito Checkstyle rule, since it did not
actually enforce the use of BDDMockito.
This commit also updates static imports to use Mockito instead of
BDDMockito where appropriate (automated via the Eclipse IDE Organize
Imports clean-up task).
Closes gh-34616
Unfortunately, it is not possible to raise the byte code level beyond
Java 1.8 for classes generated using CGLIB due to the fact that CGLIB
generates STATICHOOK methods which set static final fields outside the
initializer method <clinit> (i.e., a static initialization block).
Attempting to raise the level to Java 17 (or even Java 9) results in
exceptions like the following.
Caused by: java.lang.IllegalAccessError: Update to static final field
org.example.MyBean$$SpringCGLIB$$0.CGLIB$THREAD_CALLBACKS attempted from
a different method (CGLIB$STATICHOOK1) than the initializer method <clinit>
at org.example.MyBean$$SpringCGLIB$$0.CGLIB$STATICHOOK1(<generated>)
at org.example.MyBean$$SpringCGLIB$$0.<clinit>(<generated>)
This commit therefore introduces inline comments pointing out why we
stay with Java 1.8 byte code level with CGLIB.
See gh-34602
This commit removes the use of RepeatableContainers.of() in
AnnotationJmxAttributeSource since that is unnecessary when using the
MergedAnnotations API with @Repeatable annotations such as
@ManagedOperationParameter and @ManagedNotification.
Closes gh-34606
This commit introduces null-safe support for java.util.Optional in the
following SpEL operators:
- PropertyOrFieldReference
- MethodReference
- Indexer
- Projection
- Selection
- Elvis
Specifically, when a null-safe operator is applied to an empty
`Optional`, it will be treated as if the `Optional` were `null`, and
the subsequent operation will evaluate to `null`. However, if a
null-safe operator is applied to a non-empty `Optional`, the subsequent
operation will be applied to the object contained in the `Optional`,
thereby effectively unwrapping the `Optional`.
For example, if `user` is of type `Optional<User>`, the expression
`user?.name` will evaluate to `null` if `user` is either `null` or an
empty `Optional` and will otherwise evaluate to the `name` of the
`user`, effectively `user.get().getName()` for property access.
Note, however, that invocations of methods defined in the `Optional`
API are still supported on an empty `Optional`. For example, if `name`
is of type `Optional<String>`, the expression `name?.orElse('Unknown')`
will evaluate to "Unknown" if `name` is an empty `Optional` and will
otherwise evaluate to the `String` contained in the `Optional` if
`name` is a non-empty `Optional`, effectively `name.get()`.
Closes gh-20433
Prior to this commit, MockCookie.parse() failed with an
IllegalArgumentException when attempting to parse a custom attribute
with a value, such as "Version=1". This is a regression that was
inadvertently introduced in 7fc4937199
when adding support for the "Partitioned" attribute which does not
support a value.
This commit addresses this regression by parsing both the name and the
value from an optional, custom attribute.
See gh-31454
Closes gh-34575