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
The fix made for gh-27488 resulted in a change of the default order
of codecs. This commit reverts these changes, so that the previous
order is restored.
Closes gh-27573
This commit also applies additional clean-up tasks such as the following.
- final fields
- diamond operator (<>) for anonymous inner classes
This has only been applied to `src/main/java`.
This commit makes sure that the Reactor context from a given mono or
flux is propagated to the Flux returned by a FluxSink. This change
affects both DataBufferUtils::write and internal classes used by the
DefaultPartHttpMessageReader.
Closes gh-27517
PR gh-24470 introduced a regression for Android users by no longer
escaping closing curly braces in regular expressions.
This commit therefore partially reverts the changes made in 273812f9c5
for closing curly braces (`}`).
Closes gh27467
Previous to this commit, the specificity and quality comparators
(used by MediaType::sortByQualityValue and MediaType::sortBySpecificity)
could result in IllegalArgumentExceptions when used for sorting.
The underlying reason was that the comparators were not transitive, and
both media types with the same type, and types with the same amount of
parameters, would be considered identical by the comparator (result 0).
This commit ensures that the comparators are transitive.
Closes gh-27488
In order to catch Javadoc errors in the build, we now enable the
`Xwerror` flag for the `javadoc` tool. In addition, we now use
`Xdoclint:syntax` instead of `Xdoclint:none` in order to validate
syntax within our Javadoc.
This commit fixes all resulting Javadoc errors and warnings.
This commit also upgrades to Undertow 2.2.12.Final and fixes the
artifact names for exclusions for the Servlet and annotations APIs.
The incorrect exclusion of the Servlet API resulted in the Servlet API
being on the classpath twice for the javadoc task, which resulted in the
following warnings in previous builds.
javadoc: warning - Multiple sources of package comments found for package "javax.servlet"
javadoc: warning - Multiple sources of package comments found for package "javax.servlet.http"
javadoc: warning - Multiple sources of package comments found for package "javax.servlet.descriptor"
javadoc: warning - Multiple sources of package comments found for package "javax.servlet.annotation"
Closes gh-27480
In order to be able to use text blocks and other new Java language
features, we are upgrading to a recent version of Checkstyle.
The latest version of spring-javaformat-checkstyle (0.0.28) is built
against Checkstyle 8.32 which does not include support for language
features such as text blocks. Support for text blocks was added in
Checkstyle 8.36.
In addition, there is a binary compatibility issue between
spring-javaformat-checkstyle 0.0.28 and Checkstyle 8.42. Thus we cannot
use Checkstyle 8.42 or higher.
In this commit, we therefore upgrade to spring-javaformat-checkstyle
0.0.28 and downgrade to Checkstyle 8.41.
This change is being applied to `5.3.x` as well as `main` in order to
benefit from the enhanced checking provided in more recent versions of
Checkstyle.
Closes gh-27481
Prior to this commit, calling `StringUtils#collectionToDelimitedString`
would fail with an NPE if the collection contains null elements.
This commit ensures that null elements are converted as `"null"` in the
resulting String without failure.
See gh-27419
Includes hard JDK 9+ API dependency in CGLIB ReflectUtils (Lookup.defineClass) and removal of OutputStream spy proxy usage (avoiding invalid Mockito proxy on JDK 17)
Closes gh-26901
Migrate `CoroutinesUtils` from Kotlin code to Java and drop the
`kotlin-coroutines` module.
This update removes the need for Kotlin tooling IDE plugins to be
installed.
Closes gh-27379
This commit applies several optimizations to StringUtils#cleanPath and
related methods:
* pre-size pathElements deque in StringUtils#cleanPath with
pathElements.length elements, since this this is the maximum size and
the most likely case.
* optimize StringUtils#collectionToDelimitedString to calculate the size
of the resulting String and avoid array auto-resizing in the
StringBuilder.
* If the path did not contain any components that required cleaning,
return the (normalized) path as-is. No need to concatenate the prefix
and the trailing path.
See gh-26316
To slightly improve performance, this commit switches to
StringBuilder.append(char) instead of StringBuilder.append(String)
whenever we append a single character to a StringBuilder.
Closes gh-27098
Prior to this commit, ConfigurationClass implemented equals(),
hashCode(), and toString(), but BeanMethod did not.
This commit introduces equals(), hashCode(), and toString()
implementations in BeanMethod for consistency with ConfigurationClass
to make it possible to use BeanMethod instances to index additional
metadata as well.
In order to properly implement equals() in BeanMethod, the method
argument types are required, but these are not directly available in
BeanMethod. However, they are available via ASM when processing @Bean
methods. This commit therefore implements equals(), hashCode(), and
toString() in SimpleMethodMetadata which BeanMethod delegates to.
For completeness, this commit also implements equals(), hashCode(), and
toString() in StandardClassMetadata, StandardMethodMetadata, and
SimpleAnnotationMetadata.
Closes gh-27076
Prior to this commit, the toString() implementation did not separate
method argument types with a comma or any form of separator, leading
to results such as:
org.example.MyClass.myMethod(java.lang.Stringjava.lang.Integer)
instead of:
org.example.MyClass.myMethod(java.lang.String,java.lang.Integer)
Closes gh-27095
Proposed change aimed to keep coherence between variable declaration
and static initialization code, which stores 9 values, not 8, in these
two maps.
Closes gh-27016
Prior to this commit, in some cases application context startup steps
could be created concurrently, which could cause issues with the current
implementation tracking the parent/child relationship between steps.
This commit ensures that the flight recorder implementation is using
thread safe collection implementations for that.
Fixes gh-26941
This commit makes sure that LinkedCaseInsensitiveMap::computeIfAbsent
honors the contract of the method, and also replaces the old entry if
that mapped to null.
Closes gh-26868
This commit makes sure that LinkedCaseInsensitiveMap::putIfAbsent honors
the contract of the method, and also replaces the old entry if that
mapped to null.
Closes gh-26868
This commit adds support for Kotlin non-nullable type which resolves
to primitive Java types in BridgeMethodResolver#findBridgedMethod.
Closes gh-26585
Class.getResource, ClassLoader.getResource, and ClassLoader.getSystemResource will throw IllegalArgumentException if a malformed URL is provided to them.
According to its javadoc, resolveURL should return null if not resolvable, so catch the IllegalArgumentException and return null.
Add factory methods to `AbstractEnvironment` that allow a custom
`ConfigurablePropertyResolver` and `MutablePropertySources` instance
to be used.
See gh-26462
With the introduction of the -H:+InlineBeforeAnalysis native image
compiler flag in GraalVM 21.0.0, it is now possible to use an utility method and get code
removal at build time.
This flag will be enabled as of Spring Native 0.9.0.
closes gh-25795
This commit updates the reference manual to point out that one may use
`.` instead of `$` as the nested class separator when providing a fully
qualified class name for a nested class in XML configuration.
This commit also updates the test for ClassUtils#forName to assert
support for `.` instead of `$`.
Closes gh-26540
This commit makes sure the StringDecoder supports stripping off
multi-line delimiters, such as \r\n. Specifically, we ensure that the
delimiter is stripped from the joined buffer.
Closes gh-26511
This commit introduces computeAttribute() as an interface default method
in the AttributeAccessor API. This serves as a convenience analogous to
the computeIfAbsent() method in java.util.Map.
Closes gh-26281
HttpMessageWriter implementations now attach the request log prefix
as a hint to created data buffers when the logger associated with
the writer is at DEBUG level.
Closes gh-26230
The previous implementation uses ArrayList for storing resolved
resources and ArrayList has O(n) time complexity for the contains
operation. By switching to the HashSet for storing resolved
resources we improve the time complexity of this operation to be O(1).
See gh-25927
There are more locations which could benefit from not using a
toCharArray on a String, but rather use the charAt method from
the String itself. This to prevent an additional copy of the
char[] being created.
This commit introduces `and()` default methods in the MethodFilter and
FieldFilter functional interfaces in ReflectionUtils in order to simplify
uses cases that need to compose filter logic.
Closes gh-26063
Prior to this commit, MergedAnnotationCollectors.toAnnotationSet()
created an intermediate ArrayList for storing the results prior to
creating a LinkedHashSet in the finishing step.
Since the creation of the intermediate list is unnecessary, this commit
simplifies the implementation of toAnnotationSet() by using the
Collector.of() factory method that does not accept a `finisher` argument.
The resulting Collector internally uses a `castingIdentity()` function
as the `finisher`.
Closes gh-26031
The migration from JUnit 4 assertions to AssertJ assertions resulted in
several unnecessary casts from int to long that actually cause
assertions to pass when they should otherwise fail.
This commit fixes all such bugs for the pattern `.isNotEqualTo((long)`.
The existing implementation was exposed to very poor performance when matching
with multiple delimiters against a large buffer with many delimiters. In that
case all matchers are invoked many times (as many as the number of delimiters)
even though some of them found no match at all on the first pass.
The revised implementation uses a single index and advances all matchers
together, checking one byte a time, and not letting any one of them search to
the end of the entire buffer on a single pass.
Closes gh-25915
Simplify and optimize the processing of the input stream.
The existing implementation was using bufferUntil and creating a List
for every line along with an EndFrameBuffer inserted for the
bufferUntil predicate. So the larger the input buffer and the more
lines it contained, the greater the overhead.
The new implementation avoids bufferUntil for all lines and
instead uses concatMapIterable to aggregate the lines from a buffer
into a single list. So the larger the input buffer and the more
lines it contains, the better the throughput. The only buffering
used then is for partial chunks and those are accumulated in a list.
See gh-25915
Before this commit, ReadCompletionHandler delayed closing the channel
to allow an ongoing read to complete/fail so we can get a hold of the
associated DataBuffer and release it. This can be problematic since the
read take time to complete but even more importantly there was a race
condition where we didn't check if we've been disposed concurrently
while releasing the read flag.
This commit removes the delay and closes the channel immediately from
cancel() and that should in turn fail any ongoing read operation,
according to AsynchronousChannel, and the DataBuffer is released.
Further improvements include:
- combining the "reading" and "disposed" AtomicBoolean's into a
single "state" AtomicReference.
- an optimistic check to remain in READING mode and avoid state
switches when there is demand to continue reading.
Closes gh-25831
This commit raises the minimum Coroutines version supported
to 1.4.0-M1 and above, and changes usages of awaitFirst() or
awaitFirstOrNull() to awaitSingle() or awaitSingleOrNull()
to fix gh-25007.
Closes gh-25914
Closes gh-25007
This commit adds support for Kotlin Coroutines suspending functions to
Spring MVC, by converting those to a Mono that can then be handled by
the asynchronous request processing feature.
It also optimizes Coroutines detection with the introduction of an
optimized KotlinDetector.isSuspendingFunction() method that does not
require kotlin-reflect.
Closes gh-23611
Now that there's a new JMH infrastructure for benchmarks and that
performance tests have been rewritten to use it, we should remove the
`PERFORMANCE` `TestGroup` to avoid introducing such tests in the future.
Closes gh-24830
We are passing custom values to the constructor of PooledByteBufAllocator in
tests in order to turn of caching. This is based on:
https://github.com/netty/netty/issues/5275#issuecomment-220547057
Netty 4.1.52 has significant changes in PooledByteBufAllocator:
https://github.com/netty/netty/pull/10267
After the changes, our current value for maxOrder=2, which results in
chunkSize=16K, causes an assert failure in PoolChunk where the runSize
exceeds the chunkSize.
Prior to this commit, the subtype suffix of a MIME type (see RFC 6839)
was not properly taken into account when checking compatibility between
MIME types.
For example, `"application/*"` was not considered as compatible with
`"application/vnd.io.spring+json"`.
This commit adds a new `MimeType#getSubtypeSuffix()` method to easily
extract the subtype suffix information. This method is then reused in
the `isCompatibleWith` implementation to better handle these cases.
Fixes gh-25350
Renaming the `tags` method to `getTags` for overall consistency, and
fixing the Javadoc to mention that this returns an immutable collection.
Closes gh-25678
This commit declares each of the following public interfaces as a
@FunctionalInterface.
- org.springframework.context.ApplicationContextInitializer
- org.springframework.test.web.servlet.DispatcherServletCustomizer
- org.springframework.validation.MessageCodeFormatter
- org.springframework.util.IdGenerator
- org.springframework.beans.factory.config.YamlProcessor.MatchCallback
- org.springframework.beans.factory.config.YamlProcessor.DocumentMatcher
Closes gh-25580
Prior to this commit, if null values were supplied for the
RepeatableContainers or AnnotationFilter arguments to `from()` factory
methods in MergedAnnotations, certain operations would eventually
result in a NullPointerException. This is to be expected; however, the
NullPointerException is often swallowed and only logged at INFO level
with an exception message similar to the following.
> Failed to introspect annotations on org.example.MyClass: NullPointerException
In such cases, the INFO log message is not helpful in diagnosing the
problem. Furthermore, since the exception is swallowed, the desired
operation (e.g., MergedAnnotations.stream(...)) simply returns no
results.
This commit improves the user experience by eagerly asserting non-null
preconditions for required arguments in MergedAnnotations.from()
factory methods.
Closes gh-25568
PR gh-25429 brought it to our attention that there was a bug in
AnnotationScanner when using a non-null class filter that filtered out
classes; however, it turns out that there is no production code that
utilizes the package-private class filtering support.
This commit therefore removes all class filtering support from
AnnotationScanner since that functionality is effectively unused.
Closes gh-25477
Prior to this commit, scanning for annotations resulted in an infinite
loop when using the INHERITED_ANNOTATIONS search strategy and a class
filter that filters out visited classes.
This commit avoids an infinite loop in AnnotationsScanner's
processClassInheritedAnnotations(...) method by skipping the current
level of the class hierarchy when the current source class has been
filtered out.
Closes gh-25429
Prior to this commit, a Profiles instance created via Profiles.of() was
not considered equivalent to another Profiles instance created via
Profiles.of() with the exact same expressions. This makes it difficult
to mock invocations of Environment#acceptsProfiles(Profiles) -- for
example, when using a mocking library such as Mockito.
This commit makes Profiles instances created via Profiles.of()
"comparable" by implementing equals() and hashCode() in ParsedProfiles.
Note, however, that equivalence is only guaranteed if the exact same
profile expression strings are supplied to Profiles.of(). In other
words, Profiles.of("A & B", "C | D") is equivalent to
Profiles.of("A & B", "C | D") and Profiles.of("C | D", "A & B"), but
Profiles.of("X & Y") is not equivalent to Profiles.of("X&Y") or
Profiles.of("Y & X").
Closes gh-25340
Prior to this commit, SocketUtils used System.currentTimeMillis() for
the seed for the java.util.Random instance used internally. The use of
the milliseconds value returned by currentTimeMillis() can lead to
collisions for randomly selected free ports for tests executing in
parallel on the same computer.
This commit therefore switches to System.nanoTime() for the Random seed
used in SocketUtils in an attempt to avoid such collisions for tests
executing in parallel in different JVMs on the same computer.
Closes gh-25321
This commit removes load time weaving, CGLIB and Objenesis support
from native images.
GraalDetector has been removed for now because of
https://github.com/oracle/graal/issues/2594. It should be reintroduced
when this bug will be fixed with NativeImageDetector class name.
Closes gh-25179
This commit introduces a spring.xml.ignore system property
which when set to true avoid initializing XML infrastructure.
A typical use case is optimizing GraalVM native image footprint
for applications not using XML. In order to be effective, those
classes should be initialized at build time:
- org.springframework.util.DefaultPropertiesPersister
- org.springframework.core.io.support.PropertiesLoaderUtils
- org.springframework.web.servlet.function.support.RouterFunctionMapping
- org.springframework.web.client.RestTemplate
- org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver
- org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport
- org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
- org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter
- org.springframework.http.codec.support.BaseDefaultCodecs
- org.springframework.beans.PropertyEditorRegistrySupport
Closes gh-25151
Prior to this commit, a change to Javadoc in any class in spring-core
would result in ALL tests in the entire test suite being re-run via the
Gradle build.
Thanks to a tip from @melix, this commit aims to ensure that the
spring-core JAR is "reproducible".
Prior to this commit, a change to Javadoc in any class in spring-core
would result in ALL tests in the entire test suite being re-run via the
Gradle build.
Thanks to a tip from @melix, this commit ensures that the spring-core
JAR is "reproducible".
Commit 4000b244ff introduced new variants for noNullElements in
org.springframework.util.Assert.
This commit adds the corresponding tests to AssertTests.
Closes gh-25239
This commit avoids duplicate addition of void.class to the temporary
primitiveTypes Set in the static initialization block in ClassUtils.
Closes gh-25128
Prior to this commit (and the previous one), the `AntPathStringMatcher`
(inner class of `AntPathmatcher`) would compile `Pattern` instances and
use regex matching even for static patterns such as `"/home"`.
This change introduces a shortcut in the string matcher algorithm to
skip the `Pattern` creation and uses `String` equality instead.
Static patterns are quite common in applications and this change can
bring performance improvements, depending on the mix of patterns
configured in the web application.
In benchmarks (added with this commit), we're seeing +20% throughput
and -40% allocation. This of course can vary depending on the number of
static patterns configured in the application.
Closes gh-24887
Prior to this commit, `MediaType.parseMediaType` would already rely on
the internal LRU cache in `MimeTypeUtils` for better performance. With
that optimization, the parsing of raw media types is skipped for cached
elements.
But still, `MediaType.parseMediaType` would first get a cached
`MimeType` instance from that cache and then instantiate a
`new MediaType(type, subtype, parameters)`. This constructor not only
replays the `MimeType` checks on type/subtyme tokens and parameters, but
it also performs `MediaType`-specific checks on parameters.
Such checks are not required, as we're using an existing `MimeType`
instance in the first place.
This commit adds a new protected copy constructor (skipping checks) in
`MimeType` and uses it in `MediaType.parseMediaType` as a result.
This yields interesting performance improvements, with +400% throughput
and -40% allocation/call in benchmarks. This commit also introduces a
new JMH benchmark for future optimization work.
Closes gh-24769
Prior to this commit, the loadFactoryNames() and loadFactories() methods
in SpringFactoriesLoader effectively used a different default
ClassLoader.
This commit ensures that the ClassLoader for SpringFactoriesLoader.class
is now consistently used as the default ClassLoader.
Closes gh-24992
This commit ensures that the static cache in SpringFactoriesLoader
contains unmodifiable lists of unique names of factory implementations.
See gh-24985
Prior to this commit, SpringFactoriesLoader discovered all registered
factory implementations for a given factory type even if duplicates
were registered within a single META-INF/spring.factories file or in
multiple such files in the classpath.
This commit updates the internals of SpringFactoriesLoader so that
duplicate registrations are ignored, thereby aligning with the
well-known semantics for java.util.ServiceLoader in this regard.
Closes gh-24985
- Build Scan plugin is now Gradle Enterprise plugin applied in settings
- Compile task dependencies are now defined through classpath
- Test fixture publication can be disabled through public API
Closes gh-24384
This commit moves the toString() implementation for synthesized
annotations from TypeMappedAnnotation to
SynthesizedMergedAnnotationInvocationHandler in order to take advantage
of the synthesized annotation attribute value cache introduced in
72b1abd226.
Closes gh-24970
Prior to the introduction of the MergedAnnotation API in Spring Framework
5.2, our SynthesizedAnnotationInvocationHandler utilized a cache for
annotation attribute values; whereas, the new
SynthesizedMergedAnnotationInvocationHandler has no such caching in
place.
Issues such as gh-24961 indicate a regression in performance caused by
the lack of such an attribute value cache. For example, the required
attribute in @RequestParam is looked up using the internal meta-model
in the MergedAnnotation API twice per request for each @RequestParam in
a given controller handler method.
This commit reintroduces the attribute value cache to avoid the
unnecessary performance overhead associated with multiple lookups of
the same attribute in a synthesized annotation. This applies not only
to direct attribute method invocations but also to invocations of
equals() and hashCode() on a synthesized annotation.
Note, however, that this commit does NOT address multiple lookups of
annotation attribute values for invocations of toString(). That behavior
currently remains unchanged in the implementation of
org.springframework.core.annotation.TypeMappedAnnotation.toString().
Closes gh-24970
Commit 31fa1569c5 introduced initial support for avoiding unnecessary
annotation synthesis in the MergedAnnotation API; however, it only
avoided synthesis for annotations that do not declare any attributes.
This commit reworks this support to avoid unnecessary annotation
synthesis for annotations that declare attributes.
Specifically, this commit introduces a new `isSynthesizable()` method
in AnnotationTypeMapping that allows the "synthesizable" flag to be
computed once and cached along with the other metadata already cached
in AnnotationTypeMapping instances. TypeMappedAnnotation now delegates
to this new method when determining whether it should synthesize an
annotation.
Closes gh-24861
Prior to Spring Framework 5.2, some of our annotation utilities would
not synthesize an annotation if it was already synthesized or not
synthesizable (i.e., did not declare local aliases via @AliasFor and
did not declare attributes that could override attributes in the
meta-annotation hierarchy above the given annotation); however, we lost
most of this functionality with the introduction of the new
MergedAnnotations API.
This commit revises the implementation of createSynthesized() in
TypeMappedAnnotation so that, for invocations of
MergedAnnotation.synthesize() and indirectly for invocations of
AnnotatedElementUtils.findMergedAnnotation(), etc.:
1. An annotation that was previously synthesized will not be
synthesized again.
2. An annotation that is not "synthesizable" will not be synthesized.
For both of the above use cases, the original annotation is now
returned from createSynthesized().
Closes gh-24861