on any Spring bean or `@Bean` factory method. `RuntimeHintsRegistrar` implementations are
detected and invoked at build time.
include-code::./SpellCheckService[]
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.
{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.
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`.
Out-of-the-box, only Spring beans are considered, but you can opt-in for scanning using
In the example below, all types in the `com.example.app` package and its subpackages are considered:
{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[]
include-code::./MyConfiguration[]
@ -638,9 +643,9 @@ An example of such customization is covered in the next section.
[[aot.hints.register-reflection]]
[[aot.hints.register-reflection]]
=== `@RegisterReflection`
=== `@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`:
In the following example, public constructors and public methods can be invoked via reflection on `AccountService`:
`@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 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.
`@RegisterReflection` can be used as a meta-annotation to support more specific needs.
{spring-framework-api}/aot/hint/annotation/RegisterReflectionForBinding.html[`@RegisterReflectionForBinding`] is such composed annotation and registers the need for serializing arbitrary types.
{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.
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.
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.
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.
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) {
@ -128,16 +130,17 @@ field signature. The following listing shows the interface definition of `Generi
----
----
To implement a `GenericConverter`, have `getConvertibleTypes()` return the supported
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
TypeDescriptor)` to contain your conversion logic. The source `TypeDescriptor` provides
access to the source field that holds the value being converted. The target `TypeDescriptor`
access to the source field or method that holds the value being converted. The target
provides access to the target field where the converted value is to be set.
`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
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
and a collection. Such an `ArrayToCollectionConverter` introspects the field or method
the target collection type to resolve the collection's element type. This lets each
that declares the target collection type to resolve the collection's element type. This
element in the source array be converted to the collection element type before the
lets each element in the source array be converted to the collection element type before
collection is set on the target field.
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
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
it only when you need it. Favor `Converter` or `ConverterFactory` for basic type
@ -148,9 +151,9 @@ conversion needs.
=== Using `ConditionalGenericConverter`
=== Using `ConditionalGenericConverter`
Sometimes, you want a `Converter` to run only if a specific condition holds true. For
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
example, you might want to run a `Converter` only if a specific annotation is present on
on the target field, or you might want to run a `Converter` only if a specific method
the target field or method, or you might want to run a `Converter` only if a specific
(such as a `static valueOf` method) is defined on the target class.
method (such as a `static valueOf` method) is defined on the target type.
`ConditionalGenericConverter` is the union of the `GenericConverter` and
`ConditionalGenericConverter` is the union of the `GenericConverter` and
`ConditionalConverter` interfaces that lets you define such custom matching criteria:
`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
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
startup and then shared between multiple threads. In a Spring application, you typically
configure a `ConversionService` instance for each Spring container (or `ApplicationContext`).
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
conversion needs to be performed by the framework. You can also inject this
`ConversionService` into any of your beans and invoke it directly.
`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.
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
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`.