mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-17 16:39:29 +00:00
Merge branch '6.2.x'
This commit is contained in:
@@ -271,7 +271,7 @@ build time.
|
||||
While your application may interact with an interface that a bean implements, it is still very important to declare the most precise type.
|
||||
The AOT engine performs additional checks on the bean type, such as detecting the presence of `@Autowired` members or lifecycle callback methods.
|
||||
|
||||
For `@Configuration` classes, make sure that the return type of a `@Bean` factory method is as precise as possible.
|
||||
For `@Configuration` classes, make sure that the return type of an `@Bean` factory method is as precise as possible.
|
||||
Consider the following example:
|
||||
|
||||
[tabs]
|
||||
@@ -602,9 +602,12 @@ A number of convenient annotations are also provided for common use cases.
|
||||
[[aot.hints.import-runtime-hints]]
|
||||
=== `@ImportRuntimeHints`
|
||||
|
||||
`RuntimeHintsRegistrar` implementations allow you to get a callback to the `RuntimeHints` instance managed by the AOT engine.
|
||||
Implementations of this interface can be registered using `@ImportRuntimeHints` on any Spring bean or `@Bean` factory method.
|
||||
`RuntimeHintsRegistrar` implementations are detected and invoked at build time.
|
||||
{spring-framework-api}/aot/hint/RuntimeHintsRegistrar.html[`RuntimeHintsRegistrar`]
|
||||
implementations allow you to get a callback to the `RuntimeHints` instance managed by the
|
||||
AOT engine. Implementations of this interface can be registered using
|
||||
{spring-framework-api}/context/annotation/ImportRuntimeHints.html[`@ImportRuntimeHints`]
|
||||
on any Spring bean or `@Bean` factory method. `RuntimeHintsRegistrar` implementations are
|
||||
detected and invoked at build time.
|
||||
|
||||
include-code::./SpellCheckService[]
|
||||
|
||||
@@ -620,8 +623,10 @@ It is also possible to register an implementation statically by adding an entry
|
||||
{spring-framework-api}/aot/hint/annotation/Reflective.html[`@Reflective`] provides an idiomatic way to flag the need for reflection on an annotated element.
|
||||
For instance, `@EventListener` is meta-annotated with `@Reflective` since the underlying implementation invokes the annotated method using reflection.
|
||||
|
||||
Out-of-the-box, only Spring beans are considered, but you can opt-in for scanning using `@ReflectiveScan`.
|
||||
In the example below, all types in the `com.example.app` package and its subpackages are considered:
|
||||
Out-of-the-box, only Spring beans are considered, but you can opt-in for scanning using
|
||||
{spring-framework-api}/context/annotation/ReflectiveScan.html[`@ReflectiveScan`]. In the
|
||||
example below, all types in the `com.example.app` package and its subpackages are
|
||||
considered:
|
||||
|
||||
include-code::./MyConfiguration[]
|
||||
|
||||
@@ -638,9 +643,9 @@ An example of such customization is covered in the next section.
|
||||
[[aot.hints.register-reflection]]
|
||||
=== `@RegisterReflection`
|
||||
|
||||
{spring-framework-api}/aot/hint/annotation/RegisterReflection.html[`@RegisterReflection`] is a specialization of `@Reflective` that provides a declarative way of registering reflection for arbitrary types.
|
||||
{spring-framework-api}/aot/hint/annotation/RegisterReflection.html[`@RegisterReflection`] is a specialization of `@Reflective` that provides a declarative way to register reflection for arbitrary types.
|
||||
|
||||
NOTE: As a specialization of `@Reflective`, this is also detected if you are using `@ReflectiveScan`.
|
||||
NOTE: As a specialization of `@Reflective`, `@RegisterReflection` is also detected if you are using `@ReflectiveScan`.
|
||||
|
||||
In the following example, public constructors and public methods can be invoked via reflection on `AccountService`:
|
||||
|
||||
@@ -648,8 +653,8 @@ include-code::./MyConfiguration[tag=snippet,indent=0]
|
||||
|
||||
`@RegisterReflection` can be applied to any target type at the class level, but it can also be applied directly to a method to better indicate where the hints are actually required.
|
||||
|
||||
`@RegisterReflection` can be used as a meta-annotation to provide more specific needs.
|
||||
{spring-framework-api}/aot/hint/annotation/RegisterReflectionForBinding.html[`@RegisterReflectionForBinding`] is such composed annotation and registers the need for serializing arbitrary types.
|
||||
`@RegisterReflection` can be used as a meta-annotation to support more specific needs.
|
||||
{spring-framework-api}/aot/hint/annotation/RegisterReflectionForBinding.html[`@RegisterReflectionForBinding`] is a composed annotation that is meta-annotated with `@RegisterReflection` and registers the need for serializing arbitrary types.
|
||||
A typical use case is the use of DTOs that the container cannot infer, such as using a web client within a method body.
|
||||
|
||||
The following example registers `Order` for serialization.
|
||||
@@ -660,11 +665,66 @@ This registers hints for constructors, fields, properties, and record components
|
||||
Hints are also registered for types transitively used on properties and record components.
|
||||
In other words, if `Order` exposes others types, hints are registered for those as well.
|
||||
|
||||
[[aot.hints.convention-based-conversion]]
|
||||
=== Runtime Hints for Convention-based Conversion
|
||||
|
||||
Although the core container provides built-in support for automatic conversion of many
|
||||
common types (see xref:core/validation/convert.adoc[Spring Type Conversion]), some
|
||||
conversions are supported via a convention-based algorithm that relies on reflection.
|
||||
|
||||
Specifically, if there is no explicit `Converter` registered with the `ConversionService`
|
||||
for a particular source → target type pair, the internal `ObjectToObjectConverter`
|
||||
will attempt to use conventions to convert a source object to a target type by delegating
|
||||
to a method on the source object or to a static factory method or constructor on the
|
||||
target type. Since this convention-based algorithm can be applied to arbitrary types at
|
||||
runtime, the core container is not able to infer the runtime hints necessary to support
|
||||
such reflection.
|
||||
|
||||
If you encounter convention-based conversion issues within a native image resulting from
|
||||
lacking runtime hints, you can register the necessary hints programmatically. For
|
||||
example, if your application requires a conversion from `java.time.Instant` to
|
||||
`java.sql.Timestamp` and relies on `ObjectToObjectConverter` to invoke
|
||||
`java.sql.Timestamp.from(Instant)` using reflection, you could implement a custom
|
||||
`RuntimeHintsRegitrar` to support this use case within a native image, as demonstrated in
|
||||
the following example.
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
public class TimestampConversionRuntimeHints implements RuntimeHintsRegistrar {
|
||||
|
||||
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
|
||||
ReflectionHints reflectionHints = hints.reflection();
|
||||
|
||||
reflectionHints.registerTypeIfPresent(classLoader, "java.sql.Timestamp", hint -> hint
|
||||
.withMethod("from", List.of(TypeReference.of(Instant.class)), ExecutableMode.INVOKE)
|
||||
.onReachableType(TypeReference.of("java.sql.Timestamp")));
|
||||
}
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
`TimestampConversionRuntimeHints` can then be registered declaratively via
|
||||
<<aot.hints.import-runtime-hints>> or statically via a `META-INF/spring/aot.factories`
|
||||
configuration file.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
The above `TimestampConversionRuntimeHints` class is a simplified version of the
|
||||
`ObjectToObjectConverterRuntimeHints` class that is included in the framework and
|
||||
registered by default.
|
||||
|
||||
Thus, this specific `Instant`-to-`Timestamp` use case is already handled by the framework.
|
||||
====
|
||||
|
||||
[[aot.hints.testing]]
|
||||
=== Testing Runtime Hints
|
||||
|
||||
Spring Core also ships `RuntimeHintsPredicates`, a utility for checking that existing hints match a particular use case.
|
||||
This can be used in your own tests to validate that a `RuntimeHintsRegistrar` contains the expected results.
|
||||
This can be used in your own tests to validate that a `RuntimeHintsRegistrar` produces the expected results.
|
||||
We can write a test for our `SpellCheckService` and ensure that we will be able to load a dictionary at runtime:
|
||||
|
||||
include-code::./SpellCheckServiceTests[tag=hintspredicates]
|
||||
|
||||
@@ -72,9 +72,9 @@ When you need to centralize the conversion logic for an entire class hierarchy
|
||||
}
|
||||
----
|
||||
|
||||
Parameterize S to be the type you are converting from and R to be the base type defining
|
||||
Parameterize `S` to be the type you are converting from and `R` to be the base type defining
|
||||
the __range__ of classes you can convert to. Then implement `getConverter(Class<T>)`,
|
||||
where T is a subclass of R.
|
||||
where `T` is a subclass of `R`.
|
||||
|
||||
Consider the `StringToEnumConverterFactory` as an example:
|
||||
|
||||
@@ -107,13 +107,15 @@ Consider the `StringToEnumConverterFactory` as an example:
|
||||
[[core-convert-GenericConverter-SPI]]
|
||||
== Using `GenericConverter`
|
||||
|
||||
When you require a sophisticated `Converter` implementation, consider using the
|
||||
`GenericConverter` interface. With a more flexible but less strongly typed signature
|
||||
than `Converter`, a `GenericConverter` supports converting between multiple source and
|
||||
target types. In addition, a `GenericConverter` makes available source and target field
|
||||
context that you can use when you implement your conversion logic. Such context lets a
|
||||
type conversion be driven by a field annotation or by generic information declared on a
|
||||
field signature. The following listing shows the interface definition of `GenericConverter`:
|
||||
When you require a more sophisticated `Converter` implementation, consider using the
|
||||
`GenericConverter` interface. With a more flexible but less strongly typed signature than
|
||||
`Converter`, a `GenericConverter` supports converting between multiple source and target
|
||||
types. In addition, a `GenericConverter` is provided source and target type descriptors
|
||||
that you can use when you implement your conversion logic. Such type descriptors enable
|
||||
type conversion to be driven by an annotation on the source of the descriptor (such as a
|
||||
field or method) or by generic information declared in a field signature, method
|
||||
signature, etc. The following listing shows the definition of the `GenericConverter`
|
||||
interface:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
|
||||
----
|
||||
@@ -128,16 +130,17 @@ field signature. The following listing shows the interface definition of `Generi
|
||||
----
|
||||
|
||||
To implement a `GenericConverter`, have `getConvertibleTypes()` return the supported
|
||||
source->target type pairs. Then implement `convert(Object, TypeDescriptor,
|
||||
source → target type pairs. Then implement `convert(Object, TypeDescriptor,
|
||||
TypeDescriptor)` to contain your conversion logic. The source `TypeDescriptor` provides
|
||||
access to the source field that holds the value being converted. The target `TypeDescriptor`
|
||||
provides access to the target field where the converted value is to be set.
|
||||
access to the source field or method that holds the value being converted. The target
|
||||
`TypeDescriptor` provides access to the target field or method where the converted value
|
||||
is to be set.
|
||||
|
||||
A good example of a `GenericConverter` is a converter that converts between a Java array
|
||||
and a collection. Such an `ArrayToCollectionConverter` introspects the field that declares
|
||||
the target collection type to resolve the collection's element type. This lets each
|
||||
element in the source array be converted to the collection element type before the
|
||||
collection is set on the target field.
|
||||
and a collection. Such an `ArrayToCollectionConverter` introspects the field or method
|
||||
that declares the target collection type to resolve the collection's element type. This
|
||||
lets each element in the source array be converted to the collection element type before
|
||||
the collection is set on the target field or supplied to the target method or constructor.
|
||||
|
||||
NOTE: Because `GenericConverter` is a more complex SPI interface, you should use
|
||||
it only when you need it. Favor `Converter` or `ConverterFactory` for basic type
|
||||
@@ -148,9 +151,9 @@ conversion needs.
|
||||
=== Using `ConditionalGenericConverter`
|
||||
|
||||
Sometimes, you want a `Converter` to run only if a specific condition holds true. For
|
||||
example, you might want to run a `Converter` only if a specific annotation is present
|
||||
on the target field, or you might want to run a `Converter` only if a specific method
|
||||
(such as a `static valueOf` method) is defined on the target class.
|
||||
example, you might want to run a `Converter` only if a specific annotation is present on
|
||||
the target field or method, or you might want to run a `Converter` only if a specific
|
||||
method (such as a `static valueOf` method) is defined on the target type.
|
||||
`ConditionalGenericConverter` is the union of the `GenericConverter` and
|
||||
`ConditionalConverter` interfaces that lets you define such custom matching criteria:
|
||||
|
||||
@@ -212,7 +215,7 @@ creating common `ConversionService` configurations.
|
||||
A `ConversionService` is a stateless object designed to be instantiated at application
|
||||
startup and then shared between multiple threads. In a Spring application, you typically
|
||||
configure a `ConversionService` instance for each Spring container (or `ApplicationContext`).
|
||||
Spring picks up that `ConversionService` and uses it whenever a type
|
||||
Spring picks up that `ConversionService` and uses it whenever type
|
||||
conversion needs to be performed by the framework. You can also inject this
|
||||
`ConversionService` into any of your beans and invoke it directly.
|
||||
|
||||
@@ -249,7 +252,8 @@ It is also common to use a `ConversionService` within a Spring MVC application.
|
||||
xref:web/webmvc/mvc-config/conversion.adoc[Conversion and Formatting] in the Spring MVC chapter.
|
||||
|
||||
In certain situations, you may wish to apply formatting during conversion. See
|
||||
xref:core/validation/format.adoc#format-FormatterRegistry-SPI[The `FormatterRegistry` SPI] for details on using `FormattingConversionServiceFactoryBean`.
|
||||
xref:core/validation/format.adoc#format-FormatterRegistry-SPI[The `FormatterRegistry` SPI]
|
||||
for details on using `FormattingConversionServiceFactoryBean`.
|
||||
|
||||
|
||||
|
||||
@@ -338,7 +342,3 @@ method on the `DefaultConversionService` class.
|
||||
Converters for value types are reused for arrays and collections, so there is
|
||||
no need to create a specific converter to convert from a `Collection` of `S` to a
|
||||
`Collection` of `T`, assuming that standard collection handling is appropriate.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user