Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions content/tools/directives/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,12 @@ Arguments the SDL leaves out are filled in with their default from the directive

An enum that's only used by directive definitions doesn't need a Java class. Its values are then passed to the wiring as `String`s. Add the enum to the [type dictionary]({{< relref "/tools/schema-definition/index.md#type-dictionary" >}}) to get the enum constants instead.

Wirings run once the whole schema is built, like in graphql-java, so the types they see are the real ones and not `GraphQLTypeReference`s.

## Supported locations
Support for directives is currently limited to the following locations:
Wirings run for directives on the following locations:

* `SCALAR`
* `OBJECT`
* `FIELD_DEFINITION`
* `ARGUMENT_DEFINITION`
Expand All @@ -81,8 +84,6 @@ Support for directives is currently limited to the following locations:
* `INPUT_OBJECT`
* `INPUT_FIELD_DEFINITION`

Meaning directives for the following locations are currently not yet supported:

* `SCALAR`
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.

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" >}}).
4 changes: 2 additions & 2 deletions content/tools/getting-started/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Add the `graphql-java-tools` dependency:

```gradle
dependencies {
implementation 'io.github.graphql-java-kickstart:graphql-java-tools:14.3.0'
implementation 'io.github.graphql-java-kickstart:graphql-java-tools:14.4.0'
}
```

Expand All @@ -46,7 +46,7 @@ Add the `graphql-java-tools` dependency:
<dependency>
<groupId>io.github.graphql-java-kickstart</groupId>
<artifactId>graphql-java-tools</artifactId>
<version>14.3.0</version>
<version>14.4.0</version>
</dependency>
```

Expand Down
27 changes: 18 additions & 9 deletions content/tools/schema-definition/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ class BookResolver implements GraphQLResolver<Book> /* 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.
An optional parameter can be defined to inject the `DataFetchingEnvironment`, and must be the last argument.
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.

A resolver also applies to subclasses and implementations of its data class, so a `GraphQLResolver<Base>` resolves fields for a data class `Thing extends Base`.
A resolver for a generic class, like `GraphQLResolver<Page<?>>`, applies to every `Page<T>`.
Expand Down Expand Up @@ -150,24 +151,32 @@ SchemaParser.newParser()

The field mapping is done by name against public/protected methods and public/protected/private fields, with the following priority:

`*environmentOrContext` stands for any of `DataFetchingEnvironment`, `GraphQLContext` and the `contextClass`, in any order.

First on the resolver or root resolver (note that dataClassInstance doesn't apply for root resolvers):

1. `method <name>(dataClassInstance, *fieldArgs [, DataFetchingEnvironment])`
2. `method is<Name>(dataClassInstance, *fieldArgs [, DataFetchingEnvironment])`, only if the field returns a `Boolean`
3. `method get<Name>(dataClassInstance, *fieldArgs [, DataFetchingEnvironment])`
4. `method getField<Name>(dataClassInstance, *fieldArgs [, DataFetchingEnvironment])`
1. `method <name>(dataClassInstance, *fieldArgs [, *environmentOrContext])`
2. `method is<Name>(dataClassInstance, *fieldArgs [, *environmentOrContext])`, only if the field returns a `Boolean`
3. `method get<Name>(dataClassInstance, *fieldArgs [, *environmentOrContext])`
4. `method getField<Name>(dataClassInstance, *fieldArgs [, *environmentOrContext])`

Then on the data class:

1. `method <name>(*fieldArgs [, DataFetchingEnvironment])`
2. `method is<Name>(*fieldArgs [, DataFetchingEnvironment])`, only if the field returns a `Boolean`
3. `method get<Name>(*fieldArgs [, DataFetchingEnvironment])`
4. `method getField<Name>(*fieldArgs [, DataFetchingEnvironment])`
1. `method <name>(*fieldArgs [, *environmentOrContext])`
2. `method is<Name>(*fieldArgs [, *environmentOrContext])`, only if the field returns a `Boolean`
3. `method get<Name>(*fieldArgs [, *environmentOrContext])`
4. `method getField<Name>(*fieldArgs [, *environmentOrContext])`
5. `field <name>`

Last of all, if the data class implements`java.util.Map` then:
1. `method get(name)`

If nothing above matches, a resolver method can leave out the data class instance, as long as it ends in at least one environment or context parameter:

1. `method <name>(*fieldArgs, *environmentOrContext)`, and the `is`, `get` and `getField` forms in the same order as above

This is for fields that only need the environment, e.g. a value the parent field put in its `localContext`. It doesn't apply when `allowUnimplementedResolvers` or a missing resolver data fetcher is set, since those already handle a field with no match.


<!--*Note:* `java.util.Optional` can be used for nullable field arguments and nullable return values, and the schema parser will verify that it's not used with non-null field arguments and return values.-->

Expand Down
2 changes: 2 additions & 0 deletions content/tools/schema-parser-options/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ Options:
```
* `genericWrappers`: Allows defining your own generic classes that should be unwrapped when matching Java types to GraphQL types. You must supply the class and the index (zero-indexed) of the wrapped generic type. For example: If you want to unwrap type argument `T` of `Future<T>`, you must pass `Future.class` and `0`.
Use `GenericWrapper.withTransformer` to also convert the value at runtime. If the transformer returns `null`, the field is `null`.
Wrappers and futures nested in lists or in other wrappers are unwrapped too, e.g. `List<Try<Payload>>` or `List<CompletableFuture<Item>>`. If one element fails, the whole field fails.
A transformer or nested future that calls a DataLoader after an async step needs graphql-java's DataLoader chaining (`DataLoaderDispatchingContextKeys.setEnableDataLoaderChaining`), otherwise the field never completes.

* `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.
Expand Down