To make an analogy to read phenomena for transactional databases, this
commit effectively fixes the "Phantom Read" problem for Bean Overrides.
A phantom read occurs when the BeanOverrideBeanFactoryPostProcessor
retrieves a set of bean names by-type twice and a new bean definition
for a compatible type has been created in the BeanFactory by a
BeanOverrideHandler between the first and second retrieval.
Continue reading for the details...
Prior to this commit, the injection of test Bean Overrides (for
example, when using @MockitoBean) could fail in certain scenarios if
overrides were created for nonexistent beans "by type" without an
explicit name or qualifier. Specifically, if an override for a SubType
was created first, and subsequently an attempt was made to create an
override for a SuperType (where SubType extends SuperType), the
override for the SuperType would "override the override" for the
SubType, effectively removing the override for the SubType.
Consequently, injection of the override instance into the SubType field
would fail with an error message similar to the following.
BeanNotOfRequiredTypeException: Bean named 'Subtype#0' is expected to
be of type 'Subtype' but was actually of type 'Supertype$Mock$XHb7Aspo'
This commit addresses this issue by tracking all generated bean names
(in a generatedBeanNames set) and ensuring that a new bean override
instance is created for the current BeanOverrideHandler if a previous
BeanOverrideHandler already created a bean override instance that now
matches the type required by the current BeanOverrideHandler.
In other words, if the generatedBeanNames set already contains the
beanName that we just found by-type, we cannot "override the override",
because we would lose one of the overrides. Instead, we must create a
new override for the current handler. In the example given above, we
must end up with overrides for both SuperType and SubType.
Closes gh-34025
This commit restores the user class in generated RootBeanDefinition
instances. Previously the CGLIB subclass was exposed. While this is
important in regular runtime as the configuration class parser operates
on the bean definition, this is not relevant for AOT as this information
is internal and captured in the instance supplier.
Closes gh-33960
This commit fixes a regression in PlaceHolderParser where it would no
longer resolve nested placeholders for a case where the fallback has a
placeholder itself.
This is due to the Part implementations and how they are structure, and
this commit makes sure that nested resolution happens consistently.
Closes gh-34020
This commit restores the signature of instance suppliers that are
exposing a CGLIB proxy. While calling the CGLIB proxy itself, and
making it available in BeanInstanceSupplier, is needed internally, such
type should not be exposed as it is an internal concern.
This was breaking InstanceSupplier.andThen as it expects the public
type of the bean to be exposed, not it's eventual CGLIB subclass.
Closes gh-33998
Spring Framework 7.0 will use a Kotlin 2 baseline, using the latest 2.x
release at the time of the release.
This commit upgrades Kotlin to 2.1.0, and Kotlin Serialization and
Coroutines accordingly.
Closes gh-33629
As a preparation to using a Kotlin 2 baseline, this commit stops using
Java code snippets in Kotlin ones in order to avoid redeclaration
errors.
See gh-33629
Prior to this commit, the equals() implementation in AdvisedSupport's
MethodCacheKey only considered methods to be equal based on an identity
comparison (`==`), which led to duplicate entries in the method cache
for the same logical method.
This is caused by the fact that AdvisedSupport's
getInterceptorsAndDynamicInterceptionAdvice() method is invoked at
various stages with different Method instances for the same method:
1) when creating the proxy
2) when invoking the method via the proxy
The reason the Method instances are different is due to the following.
- Methods such as Class#getDeclaredMethods() and
Class#getDeclaredMethod() always returns "child copies" of the
underlying Method instances -- which means that `equals()` should be
used instead of (or in addition to) `==` whenever the compared Method
instances can come from different sources.
With this commit, the equals() implementation in MethodCacheKey now
considers methods equal based on identity or logical equality, giving
preference to the quicker identity check.
See gh-32586
Closes gh-33915
StandardWebSocketUpgradeStrategy is the common replacement on Tomcat, Undertow and all EE servers. JettyRequestUpgradeStrategy remains the preferred choice on Jetty.
Closes gh-33744
Prior to this commit, the reactive Scheduled tasks would be wrapped as a
`SubscribingRunnable` which does not implement a custom `toString`. This
would result in task metadata using the default Java `toString`
representation for those.
This commit ensures that the bean class name and method name are used
for this `toString`.
Closes gh-34010
Includes removal of ManagedBean and javax.annotation legacy support.
Includes AbstractJson(Http)MessageConverter revision for Yasson 3.0.
Includes initial Hibernate ORM 7.0 upgrade.
Closes gh-34011
Closes gh-33750
This commit introduces a test which verifies how many times the
matches() method of a StaticMethodMatcherPointcut is invoked during
ApplicationContext startup as well as during actual method invocations
via the advice chain, which also indirectly tests the behavior of the
equals() implementation in AdvisedSupport.MethodCacheKey.
In addition, this commit revises BeanFactoryTransactionTests to assert
that a transaction is started for the setAge() method.
See gh-33915
This commit adapts AOT support in various modules after the RuntimeHints
and related deprecation changes.
`MemberCategory.INTROSPECT_*` hints are now removed and
`MemberCategory.*_FIELDS` are replaced with
`MemberCategory.INVOKE*_FIELDS` when invocation is needed.
Usage of `RuntimeHintsAgent` are also deprecated.
Closes gh-33847
This Java agent has been designed to instrument specific JDK calls for
reflective introspection and invocations. This is useful for testing
runtime hints in integration tests.
As of GraalVM 23, there is a new VM option that does this in a much more
efficient and precise fashion. Developers can use the
`-XX:MissingRegistrationReportingMode` with the "Warn" or "Exit" value.
The option will look for reachability metadata and emit logs in "Warn"
mode or immediately exit the application with in "Exit" mode.
This commit deprecates the `RuntimeHintsAgent` in favor of this new,
more reliable option.
See gh-33847
The `RuntimeHints` API mainly reflects what is needed to write GraalVM
reachability metadata. The latest GraalVM version simplified its
format. This commit applies relevant simplifications as parts of it are
not needed anymore.
The new metadata format implies methods, constructors and fields
introspection as soon as a reflection hint is registered for a type. As
a result, `ExecutableMode.INTROSPECT`, and all `MemberCategory` values
except `MemberCategory.INVOKE_*` are being deprecated.
They have no replacement, as registering a type hint is enough.
In practice, it is enough to replace this:
```
hints.reflection().registerType(MyType.class, MemberCategory.DECLARED_FIELDS);
```
By this:
```
hints.reflection().registerType(MyType.class);
```
As for `MemberCategory.PUBLIC_FIELDS` and `MemberCategory.DECLARED_FIELDS`,
values were replaced by `INVOKE_PUBLIC_FIELDS` and
`INVOKE_DECLARED_FIELDS` to make their original intent clearer and align
with the rest of the API. Note, if you were using those values for
reflection only, you can safely remove those hints in favor of a simple
type hint.
See gh-33847
As of GraalVM 23, a new and simplified reachability metadata format is
available. Metadata now consists of a single
"reachability-metadata.json" file that contains all the information
previously spread in multiple files. The new format does not include
some introspection flags, as they're now automatically included when a
hint is registered against a type.
Also, "typeReachable" has been renamed as "typeReached" to highlight the
fact that the event considered is the static initialization of the type,
not when the static analysis performed during native compilation is
reaching the type.
This new format ships with a JSON schema, which this commit is tested
against.
See gh-33847
Prior to this commit, the resource hints for AOT applications would
generate JSON metadata with `java.util.regex.Pattern`, like:
```
{
"resources": {
"includes": [
{
"pattern": "\\Qbanner.txt\\E"
}
]
}
}
```
This regexp feature, as well as "includes" and "excludes" are not supported
anymore with the new metadata format. This commit removes the pattern
format which is now replaced by a "glob" format.
"globs" should only contain "*" (zero or more characters in a path
segment) or "**" (zero or more path segments).
Some instances of resource hint registration should be migrated as a
result.
For example, "/files/*.ext" matched both "/files/a.ext" and
"/files/folder/b.txt" in the past. The new behavior matches only the
former, unless the "/files/**/*.ext" glob pattern is used.
This commit also removes the "excludes" support, which was not widely
used and very often could lead to subtle behavior.
Closes gh-31340