Spring Framework 6.0 introduced the support infrastructure for compiling Spring applications to GraalVM Native images. If you are not familiar with GraalVM in general, how this differs from applications deployed on the JVM and what it means for Spring application, please refer to the dedicated {spring-boot-ref-docs}/native-image.html#native-image[Spring Boot 3.0 GraalVM Native Image support documentation]. Spring Boot also documents the know limitations with the GraalVM support in Spring.
Since the {spring-boot-ref-docs}/native-image.html#native-image.introducing-graalvm-native-images.key-differences-with-jvm-deployments[static analysis of your application is done at build time], GraalVM might need extra hints if your application is looking up static resources, performing reflection or creating JDK proxies at runtime.
GraphQL Java is performing three tasks at runtime that Native Images are sensible to:
-
Loading resource bundles for message internationalization
-
Some reflection on internal types for schema inspection
-
Reflection on Java types that your application registers with the schema. This happens for example when GraphQL Java is fetching properties from application types
The first two items are handled via reachability metadata that has been contributed by the Spring team to the GraalVM reachability metadata repository. This metadata is automatically fetched by the native compilation tool when building an application that depends on GraphQL Java. This doesn’t cover our third item in the list, as those types are provided by the application itself and must be discovered by another mean.
In typical Spring for GraphQL applications, Java types tied to the GraphQL schema are exposed in @Controller
method signatures
as parameters or return types. During the {spring-framework-ref-docs}/core/aot.html[Ahead Of Time processing phase] of the build,
Spring or GraphQL will use its o.s.g.data.method.annotation.support.SchemaMappingBeanFactoryInitializationAotProcessor
to discover
the relevant types and register reachability metadata accordingly.
This is all done automatically for you if you are building a Spring Boot application with GraalVM support.
If your application is "manually" registering data fetchers, some types are not discoverable as a result.
You should then register them with Spring Framework’s @RegisterReflectionForBinding
:
include-code::GraphQlConfiguration[]
<1> This application declares a RuntimeWiringConfigurer
that "manually" adds a DataFetcher
<2> Through this DataFetcher
, the BookRepository
will expose a Book
type
<3> @RegisterReflectionForBinding
will register the relevant hints for the Book
type and all types exposed as fields
The GraphQlClient
is not necessarily present as a bean in the application context and it does not expose the Java types used in the schema in method signatures.
The AotProcessor
strategy described in the section above cannot be used as a result.
For client support, Spring for GraphQL embeds the {github-main-branch}/spring-graphql/src/main/resources/META-INF/native-image/org.springframework.graphql/spring-graphql[relevant reachability metadata for the client infrastructure].
When it comes to Java types used by the application, applications should use a similar strategy as "manual" data fetchers using @RegisterReflectionForBinding
:
include-code::ProjectService[]
<1> In a Native image, we need to ensure that reflection can be performed on Project
at runtime
<2> @RegisterReflectionForBinding
will register the relevant hints for the Project
type and all types exposed as fields