This commit introduces a new registerResourceIfNecessary() method in
RuntimeHintsUtils that simplifies the registration of hints for
`classpath:` resources.
Closes gh-29083
Prior to this commit, if a ResourcePatternHint was created with a
resource pattern with a leading slash, the hint was registered and
eventually converted to configuration for the GraalVM native image
compiler.
However, such a resource pattern is invalid for GraalVM. Consequently,
the registered resources were not available within the compiled native
image.
This commit ensures that registered patterns are applicable in a native
image by preventing creation of a ResourcePatternHint with a pattern
with a leading slash.
Closes gh-29088
Prior to this commit, if the TypeReference supplied to
ResourceHintsPredicates.forResource(TypeReference,String) was for a
class declared in the default package (i.e., without a package), the
resolveAbsoluteResourceName() method incorrectly prepended two leading
slashes (//) to the absolute resource name, causing correct matches to
fail.
This commit fixes this by adding special handling for a TypeReference
without a package name. In addition, this commit introduces lenient
handling of resource names by consistently removing a leading slash in
ResourceHintsPredicates.forResource(*) methods. The latter aligns with
absolute resource path handling in other places in the framework, such
as ClassPathResource.
Closes gh-29086
This commit adds support generating graalvm `jni-config.json` file.
Configuration format for jni/reflection in graalvm is documented
to be exactly same so we can re-use facilities for reflection hints
which should be relatively clean for a user as also graalvm uses same
classes for both jni/reflection.
Closes gh-29007
This annotation and the related processor allows to
register reflection hints for data binding purpose
(class, fields, properties, record components for
the whole type hierarchy)
Closes gh-28979
This commit provides an alternative
java.beans.Introspector#findCustomizerClass implementation
via a GraalVM substitution that avoids to include thousands
of unused AWT classes in the native image.
Closes gh-29060
Since Spring no longer adds the SynthesizedAnnotation interface to the
JDK dynamic proxy used to synthesize an annotation, this commit
officially deprecates SynthesizedAnnotation and related methods in
RuntimeHintsUtils.
See gh-29041, gh-29054
Closes gh-29053
SynthesizedAnnotation was originally introduced as a convenience for
easily detecting if an annotation had been synthesized by Spring via a
simple `if (myAnnotation instanceof SynthesizedAnnotation)` check.
However, the introduction of SynthesizedAnnotation in the JDK dynamic
proxy for a synthesized annotation results in a separate proxy class
for each annotation synthesized by Spring, and this causes issues with
GraalVM native images since users and framework developers must always
ensure that the additional proxy classes are registered.
This commit completely removes the use of SynthesizedAnnotation in
synthesized annotation proxies. This change allows the proxy class for
an annotation to be reused for a synthesized annotation of the same
annotation type.
Consequently:
- Extra proxy classes are not generated on the JVM or in a native image.
- Extra proxy classes are not required to be registered for a native image.
Closes gh-29041
Add `MemberCategory` and `FieldMode` shortcuts for type registration.
Helper `builtWith` methods have also been extracted to the Hint types
to allow general reuse (for example with `registerTypes`).
See gh-29011
Add a `FieldMode` enum analogous to `ExecutableHint` and update
`FieldHint` to ensure that registration cannot downgrade `WRITE`
to `READ`.
Fixes gh-29055
Reduce the visibility of hint factory methods that return a `Builder`.
Since the `build()` method of the `Builder` is package-private the
factory methods can also be package-private.
Since SynthesizedAnnotation will be deprecated (and potentially
completely removed) in Spring Framework 6.0, this commit introduces
AnnotationUtils.isSynthesizedAnnotation(Annotation) in 5.3.x to allow
people to migrate away from relying on SynthesizedAnnotation.
Closes gh-29054
Prior to this commit, the `ConcurrentLruCache` implementation would not
perform well under certain conditions. As long as the cache capacity was
not reached, the cache would avoid maintaining an eviction queue
(reordering entries depending with least/most recently read). When the
cache capacity was reached, the LRU queue was updated for each
read/write operation. This decreased performance significantly under
contention when the capacity was reached.
This commit completely rewrites the internals of `ConcurrentLruCache`.
`ConcurrentLruCache` is now a specialized version of the
`ConcurrentLinkedHashMap` [1]. This change focuses on buferring read and
write operations, only processing them at certain times to avoid
contention.
When a cached entry is read, a read operation is queued and buffered
operations are drained if the buffer reached a fixed limit. When a new
cache entry is added or removed, a write operation is queued and
triggers a drain attempt. When the capacity is outgrown, the cache polls
items from the eviction queue, which maintains elements with the
least recently used ones first. Entries are removed until the capacity
is under control.
The behavior described here and the buffer sizes are optimized with the
number of available processors in mind. Work is localized as much as
possible on a per-thread basis to avoid contention on the eviction queue.
The new implementation has been tested with the JMH benchmark provided
here, comparing the former `COncurrentLruCache`, the new implementation
as well as the `ConcurrentLinkedHashMap` [1].
When testing with a cache reaching capacity, under contention, with a
10% cache miss, we're seeing a 40x improvement compared to the previous
implementation and performance on par with the reference.
See [2] for how to replicate the benchmark.
[1] https://github.com/ben-manes/concurrentlinkedhashmap
[2] https://github.com/spring-projects/spring-framework/wiki/Micro-Benchmarks
Closes gh-26320
This commit introduces support for Netty 5's Buffer, in the form of
Netty5DataBuffer. Because of the new API offered by Buffer, several
changes have been made to the DataBuffer API:
- CloseableDataBuffer is a simpler alternative to PooledDataBuffer, and
implemented by Netty5DataBuffer. DataBufferUtils::release can now
handle CloseableDataBuffer as well as PooledDataBuffer.
- PooledDataBuffer::touch has been moved into a separate interface:
TouchableDataBuffer, which is implemented by Netty5DataBuffer.
- The capacity of DataBuffers can no longer be reduced, they can only
grow larger. As a consequence, DataBuffer::capacity(int) has been
deprecated, but ensureWritable (formally ensureCapacity) still exists.
- DataBuffer::slice and retainedSlice have been deprecated in favor of
split, a new method that ensures that memory regions do not overlap.
- DataBuffer::asByteBuffer has been deprecated in favor of toByteBuffer,
a new method that returns a copy, instead of shared data.
- DataBufferFactory::allocateBuffer has been deprecated in favor of
allocateBuffer(int).
Closes gh-28874
This commit adapts the registration of fields, constructors, and methods
to provide the same convenience than the reflection-based one available
in ReflectionHints.
See gh-29011
This commit harmonizes the registration of an executable so that
the default method and the method that takes an empty customizer
produces the same hint. The same applies to the readable flag of
a field hint.
Rather than returning a list of executable modes, the "highest" mode
is retained.
See gh-29011
Prior to this commit, if infrastructure code working directly with an
instance of DefaultGenerationContext invoked withName() on that
instance, the new GenerationContext had to be cast from
GenerationContext to DefaultGenerationContext in order for the
infrastructure to continue working with the DefaultGenerationContext
API -- for example, the writeGeneratedContent() method which is not
defined in the GenerationContext API.
This commit makes use of a covariant return type by declaring that
DefaultGenerationContext.withName() returns a DefaultGenerationContext.
Prior to this commit, it was possible to create a DefaultGenerationContext
based on a ClassNameGenerator and GeneratedFiles; however, there was no way
to create a DefaultGenerationContext that reused an existing RuntimeHints
instance which is necessary in certain use cases -- for example, in the
TestContext framework where multiple GenerationContexts are created
based on shared instances of GeneratedFiles and RuntimeHints.
This commit addresses this by introducing a public
DefaultGenerationContext(ClassNameGenerator,GeneratedFiles,RuntimeHints)
constructor.
Based on the feedback in #28977 an easy way to create a list of
type references based on a vararg of classes is helpful when
registering the same hints for several types.
This commit updates RuntimeHintsUtils to focus on registering a JDK
proxy only as annotations of annotated elements that have at least
an introspection hints are visible out-of-the-box.
This commit also removes unnecessary hints and adapt `@Reflective` to
detect if a hint is required using the introduced
MergedAnnotation#isSynthesizable.
See gh-28967
This commit adds the ability to check if a the annotation managed by
a MergedAnnotation is synthesizable. This makes it easier to register
a JDK proxy hint if necessary
See gh-28967
The DefaultGenerationContext constructor which accepts an instance of
GeneratedClasses is now package private since GeneratedClasses can only
be created within the `org.springframework.aot.generate` package.
This commit updates ApplicationContextAotGenerator to register a
handler that process Cglib generated classes. The handler registers
such classes to the GeneratedFiles and provide a hint so that it
can be instantiated using reflection.
Closes gh-28954
Includes runtime storing of generated classes to a directory specified by the "cglib.generatedClasses" system property. Avoids lazy CGLIB fast-class generation and replaces generated Enhancer and MethodWrapper key classes with equivalent record types. Introduces support for early type determination in InstantiationStrategy, AopProxy and SmartInstantiationAwareBeanPostProcessor - in order to trigger CGLIB class generation in refreshForAotProcessing (through early determineBeanType calls for bean definitions).
Closes gh-28115
NestedIOException has been removed in Spring Framework 6 and this commit
marks it as deprecated in 5.x. Users that were relying on this exception
should use IOException directly.
Closes gh-28929
Prior to this commit, the `AbstractFileResolvingResource` would
provide a default implementation for `customizeConnection` which only
sets the HTTP request method as "HEAD".
While this is consistent with its usage within that class (in
`exists()`, `contentLength()` or `lastModified()`), this is not opened
for general usage by sub-classes.
`UrlResource` is an example of that, where its `getInputStream()` method
does not call this customization method.
This not only prevents implementations from calling
`customizeConnection` in various cases, but it also misleads developers
as they might think that customizations will be applied automatically.
This commit ensures that `customizeConnection` is called in all relevant
places and that the configuration of the HTTP method is instead done in
each method as it is use case specific.
Fixes gh-28909
Add a new `ShadowSource` Gradle task and update `spring-core.gradle`
to include source for cglib, javapoet and objenesis.
Closes gh-28892
Co-authored-by: Andy Wilkinson <wilkinsona@vmware.com>
This commit adds a dedicated method for annotations that are used as
meta-annotation when the composed annotation does not require to be
visible at runtime.
Closes gh-28887
Prior to this commit, the ApiDiff Gradle task would be configured for
all submodules of the Spring Framework project and would assume that
they all existed for the baseline version considered for the API diff.
This would cause issues when:
* the sub-project is not published as it's not an official "spring-*"
module
* the "spring-*" module is new and did not exist for the baseline
version
This commit ensures that only "spring-*" modules are considered for this
task and that we trigger an early resolution of the baseline version -
if the version doesn't exist, a warn message is logged and we assume
that this is a new module, to be compared with an empty configuration.
This commit also renames the "spring-core-graalvm" project to
"graalvm-feature", since this sub-project is not an official module
published to Maven Central, but rather an internal dependency.
Fixes gh-28818
This commit deprecates ListenableFuture in favor of CompletableFuture.
ListenableFuture was introduced in Spring Framework 4.0, when
CompletableFuture was not yet available. Spring now requires JDK 17, so
having our own type no longer seems necessary.
Major changes in this commit include:
- Deprecation of ListenableFuture and related types
(ListenableFutureCallback, SettableListenableFuture, etc.)
- Deprecation of AsyncListenableTaskExecutor in favor of default methods
in AsyncTaskExecutor (submitCompletable).
- AsyncHandlerMethodReturnValueHandler now has toCompletableFuture
instead of toListenableFuture.
- WebSocketClient now has execute methods, which do the same as
doHandshake, but return CompletableFutures (cf. the reactive
WebSocketClient).
All other changes
- add an overloaded method that takes a CompletableFuture parameter
instead of ListenableFuture, and/or
- add a method with a 'Async' suffix that returns a CompletableFuture
instead of a ListenableFuture (connectAsync, sendAsync).
Closes gh-27780
This commit polishes DefaultGenerationContext to make the method
that flushes generated classes more explicit. It now throws an
IOException and TestGenerationContext has been updated to handle
that to ease its use in code that can't throw such an exception.
As this use case is likely to happen outside the Spring Framework,
this commit adds such a convenience to spring-test as well.
Closes gh-28877
Migrate all AOT tests to make use of `GeneratedClasses` rather than
directly generating Java files. This commit also refines and polishes
AOT APIs to being greater consistency.
Specifically:
- The `MethodGenerator` interface has been removed in favor of
working directly with `GeneratedMethods`.
- The visibility of several constructors and methods has been
reduced to package-private.
- The `using(...)` and `builder` methods have been removed in
favor of setting the `Consumer` callbacks directly as
constructor arguments.
- Variable names for builders are now named `type` or `method`
depending on what they're building.
Closes gh-28831
Prior to this commit, when users wished to register proxy hints for a
Spring AOP JDK dynamic proxy, they were required to explicitly specify
SpringProxy, Advised, and DecoratingProxy along with user interfaces.
This commit simplifies hint registration for Spring AOP proxies by
introducing two completeJdkProxyInterfaces() methods in AopProxyUtils,
one that accepts strings and one that accepts classes that represent
the user-specified interfaces implemented the user component to be
proxied. The SpringProxy, Advised, and DecoratingProxy interfaces are
appended to the user-specified interfaces and returned as the complete
set of interfaces that the proxy will implement.
Closes gh-28745
Since users might not have a concrete need to work with TypeReference,
this commit introduces ProxyHints.registerJdkProxy(String...) to
simplify use of the API for registering a dynamic proxy based on fully
qualified class names of the required interfaces.
Closes gh-28781
The warning message logged for an annotation that still uses
convention-based overrides now includes a concrete suggestion for how
the problem may potentially be fixed.
WARN - Support for convention-based annotation attribute overrides is
deprecated and will be removed in Spring Framework 6.1. Please
annotate the 'locations' attribute in
@org.springframework.core.annotation.MergedAnnotationsTests$ConventionBasedComposedContextConfiguration
with an appropriate @AliasFor declaration -- for example,
@AliasFor(annotation = org.springframework.core.annotation.MergedAnnotationsTests$ContextConfiguration.class).
See gh-28760
This commit replaces convention-based annotation attribute overrides in
tests with explicit use of @AliasFor -- except for tests in spring-core,
since we still want to test our support for convention-based annotation
attribute overrides.
See gh-28760
Implicit convention-based annotation attribute overrides have been
supported for a long time; however, Spring Framework 4.2 introduced
support for explicit annotation attribute overrides via @AliasFor.
Since explicit overrides are favorable to implicit overrides, and since
the support for convention-based overrides increases the complexity of
Spring's annotation search algorithms, this commit deprecates
convention-based overrides and logs a WARNING whey the are encountered.
For example, the following message is logged for a test that still
uses convention-based overrides. A log message is generated for each
such attribute in a given annotation but only once per application run.
WARN Support for convention-based annotation attribute overrides is
deprecated and will be removed in Spring Framework 6.1. Please
annotate the 'basePackages' attribute in
@org.springframework.context.annotation.ConfigurationClassPostProcessorTests$ComposedConfigurationWithAttributeOverrides
with an appropriate @AliasFor declaration.
Closes gh-28760
AnnotationTypeMapping.addConventionMappings() sometimes adds
convention-based mappings that it should not.
For example, in certain circumstances an explicit annotation attribute
override configured via @AliasFor can be incorrectly mapped as
convention-based.
Although this does not appear to cause negative side effects (other
than unnecessary processing), this is technically a bug, and this
commit address this issue.
Closes gh-28773
Prior to this commit, a DataSize input string could not be parsed if it
contained any whitespace.
With this commit, a DataSize input string can contain leading, trailing,
or 'in between' whitespace. For example, the following will be parsed
to the same DataSize value.
- "1024B"
- "1024 B"
- " 1024B "
- " 1024 B "
Closes gh-28643
This commit fixes a NullPointerException issue in the constructor hint
predicate. Prior to this commit, a hint for a constructor was directly
looked up and dereferenced a type hint without checking if there was one
first.
This is needed as GraalVM 22.2 enabled the module system when building
native-images and all plugins have to participate in it.
See gh-28624
Closes gh-28732
Commit d6768ccc18 introduced a regression in the support for merging
annotation attributes in a multi-level annotation hierarchy.
This commit addresses that issue by ensuring that a merged annotation
is once again synthesized if a meta-annotation in the annotation
hierarchy declares attributes that override attributes in the target
annotation.
Closes gh-28716
As gh-28624 supports only static boolean fields, we still
need a few classes to be initialized at build time.
Such explicit configuration should be in theory avoidable,
so we will work with the GraalVM team to see if this can be
fixed, see for example
https://github.com/oracle/graal/issues/4673
for HttpStatus.
See gh-28624
When the ProtocolResolver SPI was introduced in Spring Framework 4.3,
support for protocol resolvers was added in DefaultResourceLoader's
getResource() implementation; however, GenericApplicationContext's
overridden getResource() implementation was not updated accordingly.
Prior to this commit, if a GenericApplicationContext was configured
with a custom ResourceLoader, registered protocol resolvers were
ignored.
This commit ensures that protocol resolvers are honored in
GenericApplicationContext even if a custom ResourceLoader is used.
Closes gh-28703
This commit prevents a StackOverflowError in
BindingReflectionHintsRegistrar when processing enum types
and refine related generated hints.
See gh-28683
Prior to this commit, meta-annotations were unnecessarily synthesized
when attempting to synthesize a MergedAnnotation retrieved via the
MergedAnnotations.from(AnnotatedElement, ...).get(<annotationType>) API.
This is a regression in our merged annotation support that was
introduced when the MergedAnnotations API replaced our previous support.
This commit fixes this by revising the logic in TypeMappedAnnotation's
createSynthesizedAnnotation() method so that a meta-annotation is
returned unmodified if it is not synthesizable.
This commit also updates BootstrapUtilsTests, since @BootstrapWith
should never have been synthesized, and Class#getCanonicalName() is
only used in the toString() implementation of an annotation synthesized
by Spring or normal annotations on Java 19+ (see
https://bugs.openjdk.org/browse/JDK-8281462).
Closes gh-28704
This commit leverages a subset of @philwebb initial experimentation
to compute at build time the value of specific boolean static fields
in native images. This enhancement is implemented for now as a
GraalVM feature.
The goal here is to keep an optimized footprint via build time code
removal without leveraging build-time class initialization which is known
for the blocking compatibility issues it introduces due to its viral nature.
For now, the static fields initialized at build time with native are:
- NativeDetector#imageCode
- Fields with a name ending by "Present" in "org.springframework" package
typically used for classpath check with ClassUtils#isPresent
Closes gh-28624
This commit moves the responsibility of naming classes to the
GenerationContext. This was already largely the case before, except that
the concept of a "mainTarget" and "featureNamePrefix" was specific
to bean factory initialization contributors.
ClassNameGenerator should now be instantiated with a default target
and an optional feature name prefix. As a result, it does no longer
generate class names in the "__" package.
GeneratedClasses can now provide a new, unique, GeneratedClass or
offer a container for retrieving the same GeneratedClass based on an
identifier. This lets all contributors use this facility rather than
creating JavaFile manually. This also means that ClassNameGenerator
is no longer exposed.
Because the naming conventions are now part of the GenerationContext, it
is required to be able to retrieve a specialized version of it if a
code generation round needs to use different naming conventions. A new
withName method has been added to that effect.
Closes gh-28585
This commit refines BindingReflectionHintsRegistrar to skip
registration of hints for Object.class, primitive types and
skip members for array types.
Closes gh-28683
When an overloaded method accepts additional "optional" arguments, we
typically declare the optional arguments after the required arguments.
For example, see the constructors for ClassPathResource.
This commit therefore revises the signature of the overloaded
forResourceLocation() method so that the optional ClassLoader argument
follows the required `String resourceLocation` argument.
As of #28620, `ResourcePatternHint` exposes its `toRegex` method.
The predicates should use it directly and mirror the exact matching
behavior.
See gh-28555
This change is done for several reasons:
- Move the logic where it is documented.
- Test it with ResourcePatternHintTests.
- Allow RuntimeHintsPredicates to leverage this logic.
Closes gh-28620
This commit adds a utility method to register a type for reflection if
it is available on the classpath. It also adds a method to register a
resource pattern if a given location is available.
Closes gh-28617
Includes deprecation of NestedServletException, whereas NestedCheckedException and NestedRuntimeException remain as base classes with several convenience methods.
Closes gh-25162
Move hints registration to spring-beans, where the actual behavior is
implemented. We chose not to move this to
`AutowiredAnnotationBeanPostProcessor` for now, as this would require it
to implement another AOT-related interface and add too much noise for
this.
See gh-28614
Prior to this commit, native images would dynamically check for the
presence of `jakarta.inject.*` annotations and might fail at runtime or
miss them entirely.
This change ensures that if such classes are present during the AOT
build, relevant runtime hints are registered so that these annotations
can be read at runtime.
Closes gh-28614
Prior to this commit, ObjectToObjectConverter considered the return
type of non-static `to[targetType.simpleName]()` methods but did not
consider the return type of static `valueOf(sourceType)`,
`of(sourceType)`, and `from(sourceType)` methods.
This led to scenarios in which `canConvert()` returned `true`, but a
subsequent `convert()` invocation resulted in a
ConverterNotFoundException, which violates the contract of the
converter.
This commit addresses this issue by taking into account the return type
of a static valueOf/of/from factory method when determining if the
ObjectToObjectConverter supports a particular conversion. Whereas the
existing check in `determineToMethod()` ensures that the method return
type is assignable to the `targetType`, the new check in
`determineFactoryMethod()` leniently ensures that the method return
type and `targetType` are "related" (i.e., reside in the same type
hierarchy).
Closes gh-28609
Support reflection-based serialization of parameters annotated
with @RequestBody and return values annotated with @ResponseBody.
It leverages a new BindingReflectionHintsRegistrar class that
is designed to register transitively the types usually needed
for binding and reflection-based serialization on fields,
constructors and properties. Generics are taken in account
as well.
Closes gh-28518
The `RuntimeHints` API allows to describe hints for the reflection,
proxies and resources behavior at runtime. The need for a particular
behavior can be covered by several types of hints, at different levels.
This knowledge can be important in several cases:
* before contributing additional hints, infrastructure can check if an
existing hint already covers the behavior
* this can be used in test suites and test infrastructure
This commit adds a new RuntimeHintsPredicates that generates `Predicate`
instances for testing `RuntimeHints` against a desired runtime behavior
for reflection, resources or proxies.
Closes gh-28555
Update `ApplicationContextAotGenerator` so that it can generate class
names based on a `target` class and using the ID of the application
context. Prior to this commit, the generated class name was always
`__.BeanFactoryRegistrations`.
Closes gh-28565
To avoid unnecessary eager initialization of DataSize.PATTERN, this
commit initializes it lazily in the first invocation of DataSize.parse
by moving PATTERN to a private static nested class.
Closes gh-28560
This commit adds a central utility to figure out if the application
must run with Ahead-Of-Time optimizations. This is mandatory for running
in a native image but can be selected on the JVM using the
"spring.aot.enabled" property.
This commit also introduces a utility that can be used to initialize a
context with generated artifacts. This represents the runtime
counterpart of ApplicationContextAotGenerator.
Closes gh-28474
Prior to this commit, the hints conditions were only supported for the
`TypeHint` case. GraalVM generally expanded this concept to all hints
and we should do the same.
Right now, only the `typeReachable` condition is available but we should
design for possible future additions.
This commit introduces a new `ConditionalHint` contract implemented by
all hints compatible with this approach. The condition information is
also used in all configuration writers as a result.
Closes gh-28126
This commit makes sure that CoroutinesUtils::invokeSuspendingFunction
treats Reactive Publisher instances the same as Kotlin Flows, i.e.
it flatmaps them.
Closes gh-27011
Attempting to name a variable in an "instanceof pattern" the same as
a field results in a Checkstyle violation similar to the following if
the "instanceof pattern matching" is located within a constructor.
Reference to instance variable 'document' needs "this.". [RequireThis]
See gh-28188
Update `RuntimeHintsUtils` to skip `@Reflective` annotations when
checking for `@AliasFor`. Since the `@Reflective` annotation is only
used at AOT processing time, we shouldn't need a hint for it.
See gh-28528
Prior to this commit, searching for classpath resources using the
"classpath*:" resource prefix did not find all applicable resources for
applications deployed as modules -- for example, when test classes and
resources are patched into the application module automatically by
Maven Surefire.
This affected component scanning -- for example, via [@]ComponentScan --
and PathMatchingResourcePatternResolver.getResources(String) in
general.
This commit addresses this by introducing first-class support for
scanning the module path when PathMatchingResourcePatternResolver's
getResources(String) method is invoked with a location pattern using
the "classpath*:" resource prefix. Specifically, getResources(String)
first searches all modules in the boot layer, excluding system modules.
It then searches the classpath using the existing Classloader-based
algorithm and returns the combined results.
Closes gh-28506
UrlResource constructors throw checked exceptions which makes it
difficult to use them in java.util.Stream and java.util.Optional APIs
or other scenarios when a checked IOException is undesirable.
To support such use cases, this commit introduces `from(URI)` and
`from(String)` factory methods in UrlResource that throw
UncheckedIOExceptions.
Closes gh-28501
This commit improves registerAnnotation to also registers the meta
annotation sources, if any. Without them, the annotation could not
be fully resolved.
See gh-28497
This commit adds a `@Reflective` annotation that can be used to declare
that the annotated element requires reflection at runtime. By default,
the annotated element is exposed but this can be customized by
specifying a dedicated `ReflectiveProcessor`.
Closes gh-28469
This commit adds a utility that takes care of registering the necessary
hints to make an annotation visible at runtime. The core framework may
create a JDK proxy if necessary, which requires specific handling.
Closes gh-28497
This commit forces the resolution of all declared constructors when
registering `RuntimeHints` for Spring factories. Resolving constructors
can throw additional `NoClassDefFoundError` at runtime and during native
image compilation, if a type exposed by the constructor is missing from
the current classloader.
See gh-27955
Update `SpringFactoriesLoader` so that `null` is never used for the
cache key. Prior to this commit, calling `forDefaultResourceLocation`
with `null` and `ClassUtils.getDefaultClassLoader()` would provide
different `SpringFactoriesLoader` instances rather than making use
of a single shared cached instance.
See gh-28416
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