Add `GeneratedMethods` and `GeneratedMethod` support classes which
can be used during code generation to generation additional methods
that will ultimately be included in a `JavaFile`.
See gh-28414
Add a `GeneratedFiles` interface that can be used to add generated
source, class and resource files. An in-memory implementation is
provided for testing and a filesystem implementation is provided
to actually save the files to disk.
See gh-28414
Add 'Throwable' variants of the `Consumer`, `Function`, `BiFunction` and
`Supplier` interfaces that wrap checked exceptions or allow calls to be
made that throw them.
Closes gh-28417
Update `SpringFactoriesLoader` so that it can load files from
arbitrary locations. An instance of the loader class itself is now
returned from static factory methods that accept different
locations.
The recent `ArgumentResolver` and `FailureHandler` `loadFactories`
variants are now no longer available as static methods. They are
still available as instance methods.
The `loadFactories` static method remains to provide
back-compatibility with Spring Framework 5.x
See gh-28416
This commit adds a `getName` to `TypeReference` that provides a way to
generate the reflection target name of a type. This typically handle
primitives (omitting the `java.lang` packages) and arrays.
Closes gh-28347
Prior to this commit, we could only contribute `RuntimeHints` through
two mechanisms:
* `AotContributingBeanFactoryPostProcessor`, consdering the entire
`BeanFactory` and designed for contributing both code and hints.
* `AotContributingBeanPostProcessor`, consdering beans one by one, but
also designed for contributing both code and hints.
There are cases where libraries and applications want to contribute
`RuntimeHints` only, in a more static fashion: a dependency being
present, or a piece of infrastructure being considered by the
application context are good enough signals to contribute hints about
resources or reflection.
This commit adds the `RuntimeHintsRegistrar` contract for these cases.
Implementations can be declared as `spring.factories` and they will be
processed as soon as they're detected on the classpath. They can also be
declared with `@ImportRuntimeHints` and they will be processed if the
annotated bean definition is considered in the application context.
This annotation should be mainly used on configuration classes and on
bean methods.
```
@Configuration
@ImportRuntimeHints(CustomRuntimeHintsRegistrar.class)
public class MyConfiguration {
@Bean
@ImportRuntimeHints(OtherRuntimeHintsRegistrar.class)
public MyBean myBean() {
//...
}
}
```
Closes gh-28160
Previously, Graal failed to build a native image as DataSize was
unintentionally initialized at build time. This commit workarounds the
faulty assumption by flagging it as safe to initialize at build-time.
Closes gh-28328
This commit updates BasicJsonWriter to handle TypeReferences and
generate an appropriate format for a class name. Specifically, an
inner class should be separated by a dollar sign, not a dot.
Closes gh-28312
Prior to this commit, the `AntPathMatcher` would inconsistently match
pattern with trailing slashes if they contain `"**"` within their
pattern.
For example `"/en/test/"` would match `"/**/test"`, but it would not
match `"/*/test"` (as it should).
This commit fixes this behavior for better consistency.
Fixes gh-27506
Since SerializationUtils#deserialize is based on Java's serialization
mechanism, it can be the source of Remote Code Execution (RCE)
vulnerabilities.
Closes gh-28075
This commit removes the deprecated TYPE_HIERARCHY_AND_ENCLOSING_CLASSES
search strategy from the MergedAnnotations model.
As a direct replacement for the TYPE_HIERARCHY_AND_ENCLOSING_CLASSES
search strategy, users can use the new fluent search API as follows.
MergedAnnotations mergedAnnotations =
MergedAnnotations.search(TYPE_HIERARCHY)
.withEnclosingClasses(clazz -> true) // always search enclosing classes
.from(MyClass.class);
Note, however, that users are highly encouraged to use
ClassUtils::isInnerClass, ClassUtils::isStaticClass, or a custom
predicate other than `clazz -> true`.
Closes gh-28080
Due to the deprecation of the TYPE_HIERARCHY_AND_ENCLOSING_CLASSES
search strategy (see gh-28079), this commit introduces a way for users
to provide a Predicate<Class<?>> that is used to decide when the
enclosing class for the class supplied to the predicate should be
searched.
This gives the user complete control over the "enclosing classes"
aspect of the search algorithm in MergedAnnotations.
- To achieve the same behavior as TYPE_HIERARCHY_AND_ENCLOSING_CLASSES,
a user can provide `clazz -> true` as the predicate.
- To limit the enclosing class search to inner classes, a user can
provide `ClassUtils::isInnerClass` as the predicate.
- To limit the enclosing class search to static nested classes, a user
can provide `ClassUtils::isStaticClass` as the predicate.
- For more advanced use cases, the user can provide a custom predicate.
For example, the following performs a search on MyInnerClass within the
entire type hierarchy and enclosing class hierarchy of that class.
MergedAnnotations mergedAnnotations =
MergedAnnotations.search(TYPE_HIERARCHY)
.withEnclosingClasses(ClassUtils::isInnerClass)
.from(MyInnerClass.class);
In addition, TestContextAnnotationUtils in spring-test has been
revised to use this new feature where feasible.
Closes gh-28207
Prior to this commit, searching for merged annotations on an
AnnotatedElement in the MergedAnnotations model was only supported via
various overloaded from(...) factory methods. In addition, it was not
possible to provide a custom AnnotationFilter without providing an
instance of RepeatableContainers.
This commit introduces a fluent API for searches in MergedAnnotations
to address these issues and improve the programming model for users of
MergedAnnotations.
To begin a search, invoke MergedAnnotations.search(SearchStrategy) with
the desired search strategy. Optional configuration can then be
provided via one of the with(...) methods. To perform a search, invoke
from(AnnotatedElement), supplying the element from which to begin the
search -- for example, a Class or a Method.
For example, the following performs a search on MyClass within the
entire type hierarchy of that class while ignoring repeatable
annotations.
MergedAnnotations mergedAnnotations =
MergedAnnotations.search(SearchStrategy.TYPE_HIERARCHY)
.withRepeatableContainers(RepeatableContainers.none())
.from(MyClass.class);
To reuse search configuration to perform the same type of search on
multiple elements, you can save the Search instance as demonstrated in
the following example.
Search search = MergedAnnotations.search(SearchStrategy.TYPE_HIERARCHY)
.withRepeatableContainers(RepeatableContainers.none());
MergedAnnotations mergedAnnotations = search.from(MyClass.class);
// do something with the MergedAnnotations for MyClass
mergedAnnotations = search.from(AnotherClass.class);
// do something with the MergedAnnotations for AnotherClass
In addition, this fluent search API paves the way for introducing
support for a predicate that controls the search on enclosing classes
(gh-28207) and subsequently for completely removing the
TYPE_HIERARCHY_AND_ENCLOSING_CLASSES search strategy (gh-28080).
Closes gh-28208
The impetus for this is to be able to use ClassUtils::isStaticClass
or the existing ClassUtils::isInnerClass as a method reference for
class-based predicates that need to differentiate between static
nested types and inner classes.
See gh-28207
This commit removes Spring's custom NestedIOException and replaces its
usage with the standard IOException which has supported a root cause
since Java 6.
Closes gh-28198
With a Java 8 baseline in place for quite some time now, it no longer
makes sense to refer to features such as annotations as "Java 5
annotations".
This commit also removes old `Tiger*Tests` classes, thereby avoiding
duplicate execution of various tests.
This commit deprecates the TYPE_HIERARCHY_AND_ENCLOSING_CLASSES search
strategy for MergedAnnotations in 6.0 M3, allowing consumers of 6.0
milestones and release candidates to provide feedback before
potentially completely removing the search strategy or providing an
alternate mechanism for achieving the same goal prior to 6.0 GA.
Closes gh-28079
See gh-28080
This commit adds a warning to the Javadoc for the
TYPE_HIERARCHY_AND_ENCLOSING_CLASSES search strategy in
MergedAnnotations with regard to the scope of the search
algorithm.
See gh-28079
This commit implements 4 package private Json serializers
for JavaSerializationHints, ProxyHints, ReflectionHints
and ResourceHints to serialize GraalVM native JSON configuration
as documented in
https://www.graalvm.org/22.0/reference-manual/native-image/BuildConfiguration/.
It exposes the related functionality via
NativeConfigurationGenerator which allows to generate the
relevant files on the filesystem via the
FileNativeConfigurationGenerator implementation.
The generated *-config.json files have been validated working
with GraalVM 22.0.
Closes gh-27991
Add an additional `FactoryInstantiationFailureHandler` strategy
interface to `SpringFactoriesLoader` to allows instantiation
failures to be handled on a per-factory bases.
For example, to log trace messages for only factories that can't
be created the following can be used:
FactoryInstantiationFailureHandler.logging(logger);
If no `FactoryInstantiationFailureHandler` instance is supplied
then `FactoryInstantiationFailureHandler.throwing()` is used
which provides back-compatible behavior by throwing an
`IllegalArgumentException`.
See gh-28057
Co-authored-by: Madhura Bhave <bhavem@vmware.com>
Co-authored-by: Andy Wilkinson <wilkinsona@vmware.com>
Update `SpringFactoriesLoader` so that factory implementation classes
can have a constructor with arguments that are resolved dynamically.
Arguments are resolved using a `ArgumentResolver` interface that is
passed to the `loadFactories` method. This strategy interface is
intentionally simple and only allows resolution based on the argument
type. A number of convenience methods are provided to allow resolvers
to be built. For example:
ArgumentResolver.of(String.class, "tests")
.and(Integer.class, 123);
Factory implementation classes must have a non-ambiguous constructor
in order to be instantiated. The `SpringFactoriesLoader` uses the same
algorithm as `BeanUtils.getResolvableConstructor`.
See gh-28057
Co-authored-by: Madhura Bhave <bhavem@vmware.com>
Co-authored-by: Andy Wilkinson <wilkinsona@vmware.com>
This commit fixes the algorithm used to analyze a generic parameter. If
a type in the generic signature is protected, the type is return rather
than the full signature. This makes sure that the appropriate package
is used. Previously, it would have incorrectly used the type of the
raw class.
Using a generic type for such a use case is wrong, and ProtectedElement
has been updated to expose a `Class` rather than a `ResolvableType`.
See gh-28030
This commit adds an infrastructure for code that generate types with the
need to write to another package if privileged access is required. An
abstraction around types where methods can be easily added is also
available as part of this commit.
Closes gh-28149
The TYPE_HIERARCHY_AND_ENCLOSING_CLASSES search strategy for
MergedAnnotations was originally introduced to support @Nested test
classes in JUnit Jupiter (see #23378).
However, while implementing #19930, we determined that the
TYPE_HIERARCHY_AND_ENCLOSING_CLASSES search strategy unfortunately
could not be used since it does not allow the user to control when to
recurse up the enclosing class hierarchy. For example, this search
strategy will automatically search on enclosing classes for static
nested classes as well as for inner classes, when the user probably
only wants one such category of "enclosing class" to be searched.
Consequently, TestContextAnnotationUtils was introduced in the Spring
TestContext Framework to address the shortcomings of the
TYPE_HIERARCHY_AND_ENCLOSING_CLASSES search strategy.
Since this search strategy is unlikely to be useful to general users,
the team has decided to deprecate this search strategy in Spring
Framework 5.3.x and remove it in 6.0.
Closes gh-28079
SocketUtils was introduced in Spring Framework 4.0, primarily to assist
in writing integration tests which start an external server on an
available random port. However, these utilities make no guarantee about
the subsequent availability of a given port and are therefore
unreliable. Instead of using SocketUtils to find an available local
port for a server, it is recommended that users rely on a server's
ability to start on a random port that it selects or is assigned by the
operating system. To interact with that server, the user should query
the server for the port it is currently using.
SocketUtils is now deprecated in 5.3.16 and will be removed in 6.0.
Closes gh-28052
In 3ec612aaf8, I accidentally removed tests that verified support for
non-synthesizable merged annotations for recursive annotations in
Kotlin.
This commit reinstates those non-synthesizable tests while retaining
the synthesizable tests.
This commit improves how protected access analysis operates. Rather than
providing a static boolean, a function callback for the member to
analyse is used. This permits to change the decision whether reflection
can be used, or if the return type is assigned.
Both of those are already applicable, with InjectionGenerator relying
on reflection for private fields, and DefaultBeanInstanceGenerator
assigning the bean instance if additional contributors are present.
This commit also moves the logic of computing the options where the code
is actually generated.
See gh-28030
This commit provides the necessary infrastructure to let components
contribute statements that are used to fully instantiate a bean
instance.
To ease code generation, a dedicated infrastructure to register bean
definition is provided in the o.s.beans.factory.generator package.
BeanDefinitionRegistrar offers a builder style API that provides a way
to hide how injected elements are resolved at runtime and let
contributors provide code that may throw a checked exception.
BeanInstanceContributor is the interface that components can implement
to contribute to a bean instance setup. DefaultBeanInstanceGenerator
generates, for a particular bean definition, the necessary statements
to instantiate a bean.
Closes gh-28047
Although Java does not allow the definition of recursive annotations,
Kotlin does, and prior to this commit an attempt to synthesize a
merged annotation using the MergedAnnotation API resulted in a
StackOverflowError if there was a recursive cycle in the annotation
definitions.
This commit addresses this issue by tracking which annotations have
already been visited and short circuits the recursive algorithm if a
cycle is detected.
Closes gh-28012
Although the initial report in gh-28015 only covered inconsistencies
for arrays and strings in the toString() implementations for
annotations between the JDK (after Java 9) and Spring, it has since
come to our attention that there was further room for improvement.
This commit therefore addresses the following in toString() output for
synthesized annotations.
- characters are now wrapped in single quotes.
- bytes are now properly formatted as "(byte) 0x##".
- long, float, and double values are now appended with "L", "f", and
"d", respectively. The use of lowercase for "f" and "d" is solely to
align with the choice made by the JDK team.
However, this commit does not address the following issues which we may
choose to address at a later point in time.
- non-ASCII, non-visible, and non-printable characters within a
character or String literal are not escaped.
- formatting for float and double values does not take into account
whether a value is not a number (NaN) or infinite.
Closes gh-28015
This commit adds an API that lets individual components contribute code,
runtime hints, and protected access information. This ease the cases
where code need to be written in a privileged package if necessary and
let contributors provide hints for the code they generate.
Closes gh-28030
This commit repackages the Javapoet library into spring-core so that it
can be used by the AOT engine without requiring a specific version.
Closes gh-27828
Since the introduction of synthesized annotation support in Spring
Framework 4.2 (a.k.a., merged annotations), the toString()
implementation attempted to align with the formatting used by the JDK
itself. However, Class annotation attributes were formatted using
Class#getName in Spring; whereas, the JDK used Class#toString up until
JDK 9.
In addition, JDK 9 introduced new formatting for toString() for
annotations, apparently intended to align with the syntax used in the
source code declaration of the annotation. However, JDK 9+ formats enum
annotation attributes using Enum#toString instead of Enum#name, which
can lead to issues if toString() is overridden in an enum.
This commit updates the formatting used for synthesized annotations by
ensuring that toString() generates a string that is compatible with the
syntax of the originating source code, going beyond the changes made in
JDK 9 by using Enum#name instead of Enum#toString.
Closes gh-28015
This commit provides an API to record the need for reflection,
resources, serialization, and proxies so that the runtime can be
optimized accordingly.
`RuntimeHints` provides an entry point to register the following:
* Reflection hints: individual elements of a type can be defined, as
well as a predefined categories (identified by the `MemberCategory`
enum). A method or constructor hint can refine whether the executable
should only be introspected or also invoked.
* Resource hints: patterns using includes/excludes identify the
resources to include at runtime. Resource bundles are also supported.
* Java Serialization hints: types that use java serialization can be
registered.
* Proxy hints: both interfaces-based (JDK) proxy and class-based proxy
can be defined.
This commit also introduces a `TypeReference` abstraction that permits
to record hints for types that are not available on the classpath, or
not compiled yet (generated code).
Closes gh-27829
Prior to this commit, the USER_DECLARED_METHODS MethodFilter in
ReflectionUtils did not actually filter methods declared in
java.lang.Object as stated in its Javadoc.
Consequently, if ReflectionUtils.doWithMethods was invoked with
USER_DECLARED_METHODS and Object.class as the class to introspect, all
non-bridge non-synthetic methods declared in java.lang.Object were
passed to the supplied MethodCallback, which breaks the contract of
USER_DECLARED_METHODS.
In addition, if USER_DECLARED_METHODS was composed with a custom
MethodFilter using `USER_DECLARED_METHODS.and(<custom MethodFilter>)`,
that composed method filter allowed all non-bridge non-synthetic
methods declared in java.lang.Object to be passed to the supplied
MethodCallback, which also breaks the contract of
USER_DECLARED_METHODS. This behavior resulted in regressions in code
that had previously used USER_DECLARED_METHODS by itself and then began
using USER_DECLARED_METHODS in a composed filter. For example, since
commit c419ea7ba7 ReflectiveAspectJAdvisorFactory has incorrectly
processed methods in java.lang.Object as candidates for advice methods.
This commit fixes this bug and associated regressions by ensuring that
USER_DECLARED_METHODS actually filters methods declared in
java.lang.Object. In addition, ReflectionUtils.doWithMethods now aborts
its search algorithm early if invoked with the USER_DECLARED_METHODS
filter and Object.class as the class to introspect.
Closes gh-27970
Prior to this commit, XmlValidationModeDetector did not properly parse
all categories of comments (described below). When such categories of
comments were encountered XmlValidationModeDetector may have
incorrectly detected that an XML file used a DTD when it used an XSD,
or vice versa.
This commit revises the parsing algorithm in XmlValidationModeDetector
so that multi-line comments and multiple comments on a single line are
properly recognized.
Specifically, with this commit the following categories of comments are
now handled properly.
- Multiple comments on a single line
- Multi-line comment: beginning on one line and then ending on another
line with an additional comment following on that same line.
- Multi-line comment: beginning at the end of XML content on one line
and then spanning multiple lines.
Closes gh-27915
Prior to this commit, our BlockHound integration tests were disabled
after the migration to a JDK 17 baseline since the build now always
runs on JDK 14 or higher.
To re-enable the tests we now supply the deprecated
-XX:+AllowRedefinitionToAddDeleteMethods command-line argument to the JVM
for tests in the Gradle build. Users can also configure this manually
within an IDE to run SpringCoreBlockHoundIntegrationTests.
If that command-line argument is removed from the JVM at some point in
the future, we will need to investigate an alternative solution.
See https://github.com/reactor/BlockHound/issues/33 for details.
In BridgeMethodResolver#isBridgedCandidateFor, candidateMethod is never
not bridged, so it's unnecessary to judge whether candidateMethod and
bridgeMethod are the same.
Closes gh-27862
Prior to this commit, the error message generated for a mismatched
number of generics did not include the information about the class in
question.
This commit improves the error message by providing more context,
specifically the result of invoking toGenericString() on the class.
For example, instead of throwing an IllegalArgumentException with the
error message "Mismatched number of generics specified", the error
message would now be "Mismatched number of generics specified for
public abstract interface java.util.Map<K,V>".
Closes gh-27847
Where unfeasible, this commit adds inline comments to explain why
try-with-resources must not be used in certain scenarios. The purpose
of the comments is to avoid accidental conversion to try-with-resources
at a later date.
Closes gh-27823
This commit replaces the use of Collections.unmodifiableList/Set/Map
with the corresponding 'of(...)' factory methods introduced in Java 9.
Closes gh-27824
This commits deprecates
- StringUtils::trimWhitespace in favor of String::strip
- StringUtils::trimLeadingWhitespace in favor of String::stripLeading
- StringUtils::trimTrailingWhitespace in favor of String::stripTrailing
Closes gh-27769
This commit makes several changes to MimeType and MediaType
related to the topic of specificity.
This commit deprecates the MimeType and MediaType Comparators.
Comparators require a transitive relationship, and the desired order for
these types is not transitive (see #27488).
Instead, this commit introduces two new MimeType methods: isMoreSpecific
and isLessSpecific, both of which return booleans. MediaType overrides
these methods to include the quality factor (q) in the comparison.
All MediaType sorting methods have been deprecated in favor of
MimeTypeUtils::sortBySpecificity. This sorting method now uses
MimeType::isLessSpecific in combination a bubble sort algorithm (which
does not require a transitive compare function).
Closes gh-27580
Since Spring Framework 6 uses JDK 17 for its baseline, we can make use
of toList() and toUnmodifiableSet() which were introduced in JDK 16 and
JDK 10, respectively.
Closes gh-27618
This commit introduces UnmodifiableMultiValueMap, an immutable wrapper
around a MultiValueMap, similar to what is returned by
Collections.unmodifiable*.
CollectionUtils::unmodifiableMultiValueMap now returns
UnmodifiableMultiValueMap.
Closes gh-27608