From 27d1b0b9e571815cdbc1faf49881e76a8f9f7fca Mon Sep 17 00:00:00 2001 From: Oryan Date: Fri, 23 Oct 2026 22:38:04 -0400 Subject: [PATCH 1/3] Document the Jackson 3 ObjectMapper options --- content/tools/schema-parser-options/index.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/content/tools/schema-parser-options/index.md b/content/tools/schema-parser-options/index.md index 00f42e2..4c86edf 100644 --- a/content/tools/schema-parser-options/index.md +++ b/content/tools/schema-parser-options/index.md @@ -32,7 +32,10 @@ Options: * `allowUnimplementedResolvers`: Defaults to `false`. Allows a schema to be created even if not all GraphQL fields have resolvers. Intended only for development, it will log a warning to remind you to turn it off for production. Any unimplemented resolvers will throw errors when queried. * `missingResolverDataFetcher`: Allows you to provide custom behavior for missing GraphQL fields. * `inputArgumentOptionalDetectOmission`: Defaults to `false`. By default, the parser will treat omitted or null method input arguments as `Optional.empty` in resolvers. If you prefer, you can disable this behavior. -* `objectMapperConfigurer` / `objectMapperProvider`: Exposes the Jackson `ObjectMapper` that handles marshalling arguments in method resolvers. Every method resolver gets its own mapper, and the configurer can configure it differently based on the GraphQL field definition. +* `objectMapperConfigurer` / `objectMapperProvider`: The Jackson `ObjectMapper` that converts the arguments of method resolvers. Since 15.0.0 it's Jackson 3 (`tools.jackson`). + By default all fields share one mapper with the Kotlin module, which fails on unknown properties and converts enums to and from Strings by `name()`. + `objectMapperConfigurer` customizes that mapper per field, and can do it differently based on the GraphQL field definition. It gets the mapper's `JsonMapper.Builder`, e.g. `.objectMapperConfigurer { builder, context -> builder.addModule(MyModule()) }`, and a module added there replaces the library's module of the same type. + `objectMapperProvider` uses your own mappers as they are, e.g. `.objectMapperProvider(field -> springMapper)` to share a Spring Boot 4 app's `JsonMapper`. * `preferGraphQLResolver`: In cases where you have a Resolver class and legacy class that conflict on type arguments, use the Resolver class instead of throwing an error. Specifically this situation can occur when you have a graphql schema type `Foo` with a `bars` property and classes: ```java @@ -70,6 +73,6 @@ Options: * `typeDefinitionFactory`: See [Type Definition Factory]({{< relref "/tools/type-definition-factory/index.md" >}}). * `includeUnusedTypes`: Defaults to `false`. By default, the parser will ignore unused type definitions in the schema. Enable this option to include them regardless. * `allowUndeclaredDirectives`: Defaults to `false`. Allows applying directives that aren't declared in the schema, e.g. the Apollo Federation directives imported through `@link`. They're only added as applied directives, with argument types guessed from their values. Directives with enum or input object arguments still have to be declared. -* `unmappedInputFields`: Defaults to `WARN`. What to do about input type fields that the class of a resolver argument has no property for. When a client sends such a field, Jackson fails to convert the argument, or drops the value if the `ObjectMapper` ignores unknown properties. - The classes are checked when the schema is built, with each field's own `ObjectMapper`, and `WARN` logs a warning for each of these fields. `FAIL` fails the build instead, and `IGNORE` skips the check. To leave a field unmapped on purpose, add it to `@JsonIgnoreProperties` on the class. +* `unmappedInputFields`: Defaults to `WARN`. What to do about input type fields that the class of a resolver argument has no property for. When a client sends such a field, Jackson fails to convert the argument, or drops the value if the `ObjectMapper` ignores unknown properties, like plain Jackson 3 and Spring Boot mappers do. + The classes are checked when the schema is built, with each field's `ObjectMapper`, and `WARN` logs a warning for each of these fields. `FAIL` fails the build instead, and `IGNORE` skips the check. To leave a field unmapped on purpose, add it to `@JsonIgnoreProperties` on the class. Classes with a custom deserializer, a builder or a delegating creator aren't checked, and neither are arguments bound to a `Map` or a `JsonNode`. From 327ba8dd222501beba2fd2467296f4334915964d Mon Sep 17 00:00:00 2001 From: Oryan Date: Sat, 24 Oct 2026 09:03:53 -0400 Subject: [PATCH 2/3] Document the rest of the tools 15.0.0 changes Bump getting started to 15.0.0 with its requirements, and update the pages that describe options removed or warnings turned into errors. --- content/tools/directives/index.md | 2 +- content/tools/getting-started/index.md | 6 ++++-- content/tools/schema-definition/index.md | 2 +- content/tools/schema-parser-options/index.md | 10 +++++----- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/content/tools/directives/index.md b/content/tools/directives/index.md index ab5da66..4954fbc 100644 --- a/content/tools/directives/index.md +++ b/content/tools/directives/index.md @@ -84,6 +84,6 @@ Wirings run for directives on the following locations: * `INPUT_OBJECT` * `INPUT_FIELD_DEFINITION` -A directive applied where its definition doesn't allow it, without a required argument, or more than once without being `repeatable` logs a warning. These will fail the build in 15.0.0. +A directive applied where its definition doesn't allow it, without a required argument, or more than once without being `repeatable` fails the build with a `SchemaError` that lists each of them with its line. Directives on `schema` and `extend schema` don't run a wiring, but they're added to the schema's applied directives. Like everywhere else, they have to be declared, unless `allowUndeclaredDirectives` is set in the [schema parser options]({{< relref "/tools/schema-parser-options/index.md" >}}). diff --git a/content/tools/getting-started/index.md b/content/tools/getting-started/index.md index e360bbc..da6f9cb 100644 --- a/content/tools/getting-started/index.md +++ b/content/tools/getting-started/index.md @@ -20,6 +20,8 @@ A working [Kotlin example](https://github.com/graphql-java-kickstart/graphql-jav To add `graphql-java-tools` to your project and get started quickly, do the following. +Version 15 needs Java 17, graphql-java 26 and Jackson 3. graphql-spring-boot-starter doesn't support it yet, so stay on 14.5.0 with it. + ### Build with Gradle Make sure `mavenCentral` is amongst your repositories: @@ -34,7 +36,7 @@ Add the `graphql-java-tools` dependency: ```gradle dependencies { - implementation 'io.github.graphql-java-kickstart:graphql-java-tools:14.5.0' + implementation 'io.github.graphql-java-kickstart:graphql-java-tools:15.0.0' } ``` @@ -46,7 +48,7 @@ Add the `graphql-java-tools` dependency: io.github.graphql-java-kickstart graphql-java-tools - 14.5.0 + 15.0.0 ``` diff --git a/content/tools/schema-definition/index.md b/content/tools/schema-definition/index.md index bd10454..65b7d95 100644 --- a/content/tools/schema-definition/index.md +++ b/content/tools/schema-definition/index.md @@ -109,7 +109,7 @@ class BookResolver implements GraphQLResolver /* This class is a resolver When given a `BookResolver` instance, GraphQL Java Tools first attempts to map fields to methods on the resolver before mapping them to fields or methods on the data class. If there is a matching method on the resolver, the data class instance is passed as the first argument to the resolver function. This does not apply to root resolvers, since those don't have a data class to resolve for. The field's arguments come next, in order. -After them, a method can take any of `DataFetchingEnvironment`, `GraphQLContext` and the `contextClass` set in the [schema parser options]({{< relref "/tools/schema-parser-options/index.md" >}}), in any order. +After them, a method can take any of `DataFetchingEnvironment`, `GraphQLContext` and the `contextClass` set in the [schema parser options]({{< relref "/tools/schema-parser-options/index.md" >}}), in any order. A method that takes one of these in an argument's place fails the build. A resolver also applies to subclasses and implementations of its data class, so a `GraphQLResolver` resolves fields for a data class `Thing extends Base`. A resolver for a generic class, like `GraphQLResolver>`, applies to every `Page`. diff --git a/content/tools/schema-parser-options/index.md b/content/tools/schema-parser-options/index.md index d398914..18b0fcd 100644 --- a/content/tools/schema-parser-options/index.md +++ b/content/tools/schema-parser-options/index.md @@ -30,7 +30,7 @@ Options: * `useDefaultGenericWrappers`: Defaults to `true`. Tells the parser whether or not to add it's own list of well-known generic wrappers, such as `Future` and `CompletableFuture`. graphql-java only waits on a `CompletionStage`, so a method declared to return a `Future` has to return one, such as a `CompletableFuture`. Any other future fails the field with an error, unless a generic wrapper transformer converts it. * `allowUnimplementedResolvers`: Defaults to `false`. Allows a schema to be created even if not all GraphQL fields have resolvers. Intended only for development, it will log a warning to remind you to turn it off for production. Any unimplemented resolvers will throw errors when queried. -* `missingResolverDataFetcher`: Allows you to provide custom behavior for missing GraphQL fields. +* `missingResolverDataFetcherProvider`: Allows you to provide custom behavior for missing GraphQL fields. It gets the field definition and the options, and returns the `DataFetcher` for that field, e.g. `.missingResolverDataFetcherProvider { field, options -> fetcher }`. * `inputArgumentOptionalDetectOmission`: Defaults to `false`. By default, the parser will treat omitted or null method input arguments as `Optional.empty` in resolvers. If you prefer, you can disable this behavior. * `objectMapperConfigurer` / `objectMapperProvider`: The Jackson `ObjectMapper` that converts the arguments of method resolvers. Since 15.0.0 it's Jackson 3 (`tools.jackson`). By default all fields share one mapper with the Kotlin module, which fails on unknown properties and converts enums to and from Strings by `name()`. @@ -60,8 +60,10 @@ Options: * Guice * Spring AOP * Weld -* `introspectionEnabled`: Deprecated, and will be removed in 15.0.0. Defaults to `true`. When set to `false`, every field of the introspection types is hidden, so an introspection query fails validation. - Turn introspection off with graphql-java instead, for the whole JVM or for one request: + + A resolver that is a JDK dynamic proxy fails the build, since its methods can't be called on the proxy. Use class-based proxies, e.g. `proxyTargetClass = true` in Spring. +* `fieldVisibility`: Provide a graphql field visibility implementation. See [Field Visibility](https://www.graphql-java.com/documentation/field-visibility). + To turn introspection off, use graphql-java's switches, for the whole JVM or for one request: ```java Introspection.enabledJvmWide(false); @@ -69,8 +71,6 @@ Options: .query(query) .graphQLContext(Map.of(Introspection.INTROSPECTION_DISABLED, true)); ``` - An introspection query then fails with an "introspection disabled" error when it runs. -* `fieldVisibility`: Provide a graphql field visibility implementation. This option overrides `introspectionEnabled` when used. See [Field Visibility](https://www.graphql-java.com/documentation/field-visibility). * `coroutineContext` / `coroutineContextProvider`: Provide a kotlin coroutine context to be used with suspend functions of resolvers. A suspend function runs on the calling thread until it first suspends, and continues on this context after that, so wrap blocking calls in `withContext(Dispatchers.IO)`. To run them in your own `CoroutineScope`, e.g. to cancel them with the request, put it in the execution input's context: From 3b6c38394e0686492b9cddb17c7453c10e735275 Mon Sep 17 00:00:00 2001 From: Oryan Date: Sat, 24 Oct 2026 09:06:10 -0400 Subject: [PATCH 3/3] Say graphql-spring-boot-starter is archived --- content/tools/getting-started/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/tools/getting-started/index.md b/content/tools/getting-started/index.md index da6f9cb..00a3607 100644 --- a/content/tools/getting-started/index.md +++ b/content/tools/getting-started/index.md @@ -20,7 +20,7 @@ A working [Kotlin example](https://github.com/graphql-java-kickstart/graphql-jav To add `graphql-java-tools` to your project and get started quickly, do the following. -Version 15 needs Java 17, graphql-java 26 and Jackson 3. graphql-spring-boot-starter doesn't support it yet, so stay on 14.5.0 with it. +Version 15 needs Java 17, graphql-java 26 and Jackson 3. graphql-spring-boot-starter is archived and doesn't work with it, so stay on 14.5.0 with the starter. ### Build with Gradle