Prior to this commit, searches for non-public repeatable annotations
failed with error messages similar to the following, since the
repeatable annotation's container's `value()` method could not be
invoked via reflection.
JDK 8:
java.lang.IllegalAccessError: tried to access class
org.springframework.core.annotation.NestedRepeatableAnnotationsTests$A
from class com.sun.proxy.$Proxy12
JDK 17:
java.lang.IllegalAccessError: failed to access class
org.springframework.core.annotation.NestedRepeatableAnnotationsTests$A
from class jdk.proxy2.$Proxy12
(org.springframework.core.annotation.NestedRepeatableAnnotationsTests$A
is in unnamed module of loader 'app'; jdk.proxy2.$Proxy12 is in module
jdk.proxy2 of loader 'app')
This commit makes it possible to search for non-public repeatable
annotations by first attempting to invoke the repeatable annotation's
container's `value()` method via the container's InvocationHandler (if
the container is a JDK dynamic proxy) and then falling back to
reflection for the method invocation if an error occurs (such as a
SecurityException).
Closes gh-29301
This commit is a follow up to 828f74f71a
and applies to same fix for getMergedRepeatableAnnotations().
See the previous commit for details.
Closes gh-20279
Prior to this commit, the findMergedRepeatableAnnotations() methods in
AnnotatedElementUtils failed to find repeatable annotations declared
on other repeatable annotations (i.e., when one repeatable annotation
type was used as a meta-annotation on a different repeatable annotation
type).
The reason is that
findMergedRepeatableAnnotations(element, annotationType, containerType)
always used RepeatableContainers.of(annotationType, containerType) to
create a RepeatableContainers instance, even if the supplied
containerType was null. Doing so restricts the search to supporting
only repeatable annotations whose container is the supplied
containerType and prevents the search from finding repeatable
annotations declared as meta-annotations on other types of repeatable
annotations.
Note, however, that direct use of the MergedAnnotations API already
supported finding nested repeatable annotations when using
RepeatableContainers.standardRepeatables() or
RepeatableContainers.of(...).and(...).and(...). The latter composes
support for multiple repeatable annotation types and their containers.
This commit addresses the issue for findMergedRepeatableAnnotations()
when the containerType is null or not provided.
However, findMergedRepeatableAnnotations(element, annotationType, containerType)
still suffers from the aforementioned limitation, and the Javadoc has
been updated to make that clear.
Closes gh-20279
This commit makes sure that `@ExceptionHandler`-annotated methods can be
invoked via reflection in a native image. As most of the handling of
the parameter and the return type is shared with our generic
RequestMapping handling, the ReflectiveProcessor extends from it.
An `@ExceptionHandler`-annotated method can return a `ProblemDetail`. If
that's the case, reflection entries are contributed.
Closes gh-29297
In order to keep the maximum of flexibility, this commit makes
shouldSkipType and shouldSkipMembers methods private.
That will allow for example to refactor
BindingReflectionHintsRegistrar in order to support skipping
custom classes specified via @RegisterReflectionForBinding
without having to subclass it.
See gh-29279
This commit makes sure that hints are registered for CGLIB proxies even
if the proxy itself is not created. This typically happens when AOT runs
on an existing classpath, and a previous run already created the proxy.
Closes gh-29295
There's currently a considerable amount of overlap between the
implementations of AotProcessor and TestAotProcessor. In addition
AotProcessor is abstract and does not include a main() method; whereas,
TestAotProcessor is concrete and does include a main() method.
To address these issues, this commit:
- Introduces an AbstractAotProcessor base class that AotProcessor and
TestAotProcessor now both extend
- Moves common properties/functionality to AbstractAotProcessor
- Renames AotProcessor to ContextAotProcessor
- Makes TestAotProcessor abstract like ContextAotProcessor
- Removes the main() method from TestAotProcessor
Closes gh-29266
This commit improves the exception message thrown by MultipartParser
when it cannot find the end of the multipart body, by showing in the
message what the parser is looking for (CRLF--<boundary>).
Closes gh-28067
SQLErrorCodeSQLExceptionTranslator#USER_PROVIDED_ERROR_CODES_FILE_PRESENT
evaluation at build time combined with the lazy
SQLErrorCodesFactory#instance initialization allow to
avoid making SQLErrorCodesFactory constructor reachable
when no custom sql-error-codes.xml is provided.
Closes gh-29294
This commit also removes ResourcePropertiesPersister which
was introduced in 5.3 specifically for spring.xml.ignore
flag and which is expected to be used only internally by
Spring Framework. DefaultPropertiesPersister should be used
instead.
Closes gh-29277
Prior to this commit, the AOT runtime support in the Spring TestContext
Framework (TCF) relied on the MergedContextConfiguration for a given
test class being the same as during the AOT processing phase. However,
this is not always the case. For example, Spring Boot "disables"
selected `ContextCustomizer` implementations during AOT runtime
execution.
See 0f325f98b5
To address that, this commit ensures that context caching works
properly during AOT runtime execution even if the
MergedContextConfiguration differs from what was produced during the
AOT processing phase. Specifically, this commit introduces
AotMergedContextConfiguration which is a MergedContextConfiguration
implementation based on an AOT-generated ApplicationContextInitializer.
AotMergedContextConfiguration wraps the MergedContextConfiguration
built during AOT runtime execution.
Interactions with the ContextCache are performed using the
AotMergedContextConfiguration; whereas, the ApplicationContext is
loaded using the original MergedContextConfiguration.
This commit also introduces a ContextCustomizerFactory that emulates
the ImportsContextCustomizerFactory in Spring Boot's testing support.
BasicSpringJupiterImportedConfigTests uses @Import to verify that the
context customizer works, and AotIntegrationTests has been updated to
execute BasicSpringJupiterImportedConfigTests after test classes whose
MergedContextConfiguration is identical during AOT runtime execution.
Without the fix in this commit, BasicSpringJupiterImportedConfigTests
would fail in AOT runtime mode since its ApplicationContext would be
pulled from the cache using an inappropriate cache key.
Closes gh-29289
Prior to this commit, the abstract base test classes for JUnit 4 and
TestNG registered explicit sets of TestExecutionListeners. This
configuration was useful in the early years of the Spring TestContext
Framework. However, since the introduction of support for automatic
registration of "default" listeners in Spring Framework 4.1, these
predefined sets of TestExecutionListeners have become a hindrance to
using Spring's testing support with default listeners from Spring
portfolio projects (such as Spring Boot and Spring Security) as well as
third-party or project-specific default listeners.
To address this issue, the four abstract base test classes for JUnit 4
and TestNG no longer declare listeners via @TestExecutionListeners and
instead now rely on registration of default listeners.
Closes gh-29149
Prior to this commit, ExchangeResult.assertWithDiagnostics() threw an
IllegalArgumentException for a custom HTTP status code since toString()
invoked getStatus() without a try-catch block.
This commit addresses this issue by introducing a formatStatus() method
that defensively formats the response status, initially trying to
format the HttpStatus and falling back to formatting the raw integer
status code.
Closes gh-29283