@PublicSpi public abstract class ExecutionStrategy extends java.lang.Object
query { friends { id name friends { id name } } enemies { id name allies { id name } } }
Given the graphql query above, an execution strategy will be called for the top level fields 'friends' and 'enemies' and it will be asked to find an object to describe them. Because they are both complex object types, it needs to descend down that query and start fetching and completing fields such as 'id','name' and other complex fields such as 'friends' and 'allies', by recursively calling to itself to execute these lower field layers
The execution of a field has two phases, first a raw object must be fetched for a field via a DataFetcher
which
is defined on the GraphQLFieldDefinition
. This object must then be 'completed' into a suitable value, either as a scalar/enum type via
coercion or if its a complex object type by recursively calling the execution strategy for the lower level fields.
The first phase (data fetching) is handled by the method fetchField(ExecutionContext, ExecutionStrategyParameters)
The second phase (value completion) is handled by the methods completeField(ExecutionContext, ExecutionStrategyParameters, Object)
and the other "completeXXX" methods.
The order of fields fetching and completion is up to the execution strategy. As the graphql specification http://facebook.github.io/graphql/#sec-Normal-and-Serial-Execution says:
Normally the executor can execute the entries in a grouped field set in whatever order it chooses (often in parallel). Because the resolution of fields other than top-level mutation fields must always be side effect-free and idempotent, the execution order must not affect the result, and hence the server has the freedom to execute the field entries in whatever order it deems optimal.
So in the case above you could execute the fields depth first ('friends' and its sub fields then do 'enemies' and its sub fields or it
could do breadth first ('fiends' and 'enemies' data fetch first and then all the sub fields) or in parallel via asynchronous
facilities like CompletableFuture
s.
execute(ExecutionContext, ExecutionStrategyParameters)
is the entry point of the execution strategy.
Modifier and Type | Field and Description |
---|---|
protected DataFetcherExceptionHandler |
dataFetcherExceptionHandler |
protected FieldCollector |
fieldCollector |
protected ValuesResolver |
valuesResolver |
Modifier | Constructor and Description |
---|---|
protected |
ExecutionStrategy()
The default execution strategy constructor uses the
SimpleDataFetcherExceptionHandler
for data fetching errors. |
protected |
ExecutionStrategy(DataFetcherExceptionHandler dataFetcherExceptionHandler)
The consumers of the execution strategy can pass in a
DataFetcherExceptionHandler to better
decide what do when a data fetching error happens |
Modifier and Type | Method and Description |
---|---|
protected void |
assertNonNullFieldPrecondition(NonNullableFieldWasNullException e)
See (http://facebook.github.io/graphql/#sec-Errors-and-Non-Nullability),
|
protected void |
assertNonNullFieldPrecondition(NonNullableFieldWasNullException e,
java.util.concurrent.CompletableFuture<?> completableFuture) |
protected FieldValueInfo |
completeField(ExecutionContext executionContext,
ExecutionStrategyParameters parameters,
java.lang.Object fetchedValue)
Called to complete a field based on the type of the field.
|
protected FieldValueInfo |
completeValue(ExecutionContext executionContext,
ExecutionStrategyParameters parameters)
Called to complete a value for a field based on the type of the field.
|
protected java.util.concurrent.CompletableFuture<ExecutionResult> |
completeValueForEnum(ExecutionContext executionContext,
ExecutionStrategyParameters parameters,
GraphQLEnumType enumType,
java.lang.Object result)
Called to turn an object into a enum value according to the
GraphQLEnumType by asking that enum type to coerce the object into a valid value |
protected FieldValueInfo |
completeValueForList(ExecutionContext executionContext,
ExecutionStrategyParameters parameters,
java.lang.Iterable<java.lang.Object> iterableValues)
Called to complete a list of value for a field based on a list type.
|
protected FieldValueInfo |
completeValueForList(ExecutionContext executionContext,
ExecutionStrategyParameters parameters,
java.lang.Object result)
Called to complete a list of value for a field based on a list type.
|
protected java.util.concurrent.CompletableFuture<ExecutionResult> |
completeValueForObject(ExecutionContext executionContext,
ExecutionStrategyParameters parameters,
GraphQLObjectType resolvedObjectType,
java.lang.Object result)
Called to turn an java object value into an graphql object value
|
protected java.util.concurrent.CompletableFuture<ExecutionResult> |
completeValueForScalar(ExecutionContext executionContext,
ExecutionStrategyParameters parameters,
GraphQLScalarType scalarType,
java.lang.Object result)
Called to turn an object into a scalar value according to the
GraphQLScalarType by asking that scalar type to coerce the object
into a valid value |
abstract java.util.concurrent.CompletableFuture<ExecutionResult> |
execute(ExecutionContext executionContext,
ExecutionStrategyParameters parameters)
This is the entry point to an execution strategy.
|
protected java.util.concurrent.CompletableFuture<java.lang.Object> |
fetchField(ExecutionContext executionContext,
ExecutionStrategyParameters parameters)
Called to fetch a value for a field from the
DataFetcher associated with the field
GraphQLFieldDefinition . |
protected ExecutionTypeInfo |
fieldTypeInfo(ExecutionStrategyParameters parameters,
GraphQLFieldDefinition fieldDefinition)
Builds the type info hierarchy for the current field
|
protected GraphQLFieldDefinition |
getFieldDef(ExecutionContext executionContext,
ExecutionStrategyParameters parameters,
Field field)
Called to discover the field definition give the current parameters and the AST
Field |
protected GraphQLFieldDefinition |
getFieldDef(GraphQLSchema schema,
GraphQLObjectType parentType,
Field field)
Called to discover the field definition give the current parameters and the AST
Field |
protected ExecutionResult |
handleNonNullException(ExecutionContext executionContext,
java.util.concurrent.CompletableFuture<ExecutionResult> result,
java.lang.Throwable e) |
static java.lang.String |
mkNameForPath(Field currentField) |
static java.lang.String |
mkNameForPath(java.util.List<Field> currentField) |
protected java.util.concurrent.CompletableFuture<ExecutionResult> |
resolveField(ExecutionContext executionContext,
ExecutionStrategyParameters parameters)
Called to fetch a value for a field and resolve it further in terms of the graphql query.
|
protected java.util.concurrent.CompletableFuture<FieldValueInfo> |
resolveFieldWithInfo(ExecutionContext executionContext,
ExecutionStrategyParameters parameters)
Called to fetch a value for a field and its extra runtime info and resolve it further in terms of the graphql query.
|
protected GraphQLObjectType |
resolveType(ExecutionContext executionContext,
ExecutionStrategyParameters parameters,
GraphQLType fieldType) |
protected GraphQLObjectType |
resolveTypeForInterface(TypeResolutionParameters params)
Called to resolve a
GraphQLInterfaceType into a specific GraphQLObjectType so the object can be executed in terms of that type |
protected GraphQLObjectType |
resolveTypeForUnion(TypeResolutionParameters params)
Called to resolve a
GraphQLUnionType into a specific GraphQLObjectType so the object can be executed in terms of that type |
protected java.lang.Iterable<java.lang.Object> |
toIterable(ExecutionContext context,
ExecutionStrategyParameters parameters,
java.lang.Object result) |
protected java.lang.Iterable<java.lang.Object> |
toIterable(java.lang.Object result)
Converts an object that is known to should be an Iterable into one
|
protected java.lang.Object |
unboxPossibleOptional(java.lang.Object result)
We treat Optional objects as "boxed" values where an empty Optional
equals a null object and a present Optional is the underlying value.
|
protected final ValuesResolver valuesResolver
protected final FieldCollector fieldCollector
protected final DataFetcherExceptionHandler dataFetcherExceptionHandler
protected ExecutionStrategy()
SimpleDataFetcherExceptionHandler
for data fetching errors.protected ExecutionStrategy(DataFetcherExceptionHandler dataFetcherExceptionHandler)
DataFetcherExceptionHandler
to better
decide what do when a data fetching error happensdataFetcherExceptionHandler
- the callback invoked if an exception happens during data fetchingpublic abstract java.util.concurrent.CompletableFuture<ExecutionResult> execute(ExecutionContext executionContext, ExecutionStrategyParameters parameters) throws NonNullableFieldWasNullException
executionContext
- contains the top level execution parametersparameters
- contains the parameters holding the fields to be executed and source objectExecutionResult
NonNullableFieldWasNullException
- in the future if a non null field resolves to a null valueprotected java.util.concurrent.CompletableFuture<ExecutionResult> resolveField(ExecutionContext executionContext, ExecutionStrategyParameters parameters)
ExecutionResult
is returned.
An execution strategy can iterate the fields to be executed and call this method for each one
Graphql fragments mean that for any give logical field can have one or more Field
values associated with it
in the query, hence the fieldList. However the first entry is representative of the field for most purposes.
executionContext
- contains the top level execution parametersparameters
- contains the parameters holding the fields to be executed and source objectExecutionResult
NonNullableFieldWasNullException
- in the future if a non null field resolves to a null valueprotected java.util.concurrent.CompletableFuture<FieldValueInfo> resolveFieldWithInfo(ExecutionContext executionContext, ExecutionStrategyParameters parameters)
FieldValueInfo
is returned.
An execution strategy can iterate the fields to be executed and call this method for each one
Graphql fragments mean that for any give logical field can have one or more Field
values associated with it
in the query, hence the fieldList. However the first entry is representative of the field for most purposes.
executionContext
- contains the top level execution parametersparameters
- contains the parameters holding the fields to be executed and source objectFieldValueInfo
NonNullableFieldWasNullException
- in the FieldValueInfo.getFieldValue()
future if a non null field resolves to a null valueprotected java.util.concurrent.CompletableFuture<java.lang.Object> fetchField(ExecutionContext executionContext, ExecutionStrategyParameters parameters)
DataFetcher
associated with the field
GraphQLFieldDefinition
.
Graphql fragments mean that for any give logical field can have one or more Field
values associated with it
in the query, hence the fieldList. However the first entry is representative of the field for most purposes.
executionContext
- contains the top level execution parametersparameters
- contains the parameters holding the fields to be executed and source objectNonNullableFieldWasNullException
- in the future if a non null field resolves to a null valueprotected FieldValueInfo completeField(ExecutionContext executionContext, ExecutionStrategyParameters parameters, java.lang.Object fetchedValue)
If the field is a scalar type, then it will be coerced and returned. However if the field type is an complex object type, then the execution strategy will be called recursively again to execute the fields of that type before returning.
Graphql fragments mean that for any give logical field can have one or more Field
values associated with it
in the query, hence the fieldList. However the first entry is representative of the field for most purposes.
executionContext
- contains the top level execution parametersparameters
- contains the parameters holding the fields to be executed and source objectfetchedValue
- the fetched raw valueFieldValueInfo
NonNullableFieldWasNullException
- in the FieldValueInfo.getFieldValue()
future if a non null field resolves to a null valueprotected FieldValueInfo completeValue(ExecutionContext executionContext, ExecutionStrategyParameters parameters) throws NonNullableFieldWasNullException
If the field is a scalar type, then it will be coerced and returned. However if the field type is an complex object type, then the execution strategy will be called recursively again to execute the fields of that type before returning.
Graphql fragments mean that for any give logical field can have one or more Field
values associated with it
in the query, hence the fieldList. However the first entry is representative of the field for most purposes.
executionContext
- contains the top level execution parametersparameters
- contains the parameters holding the fields to be executed and source objectFieldValueInfo
NonNullableFieldWasNullException
- if a non null field resolves to a null valueprotected FieldValueInfo completeValueForList(ExecutionContext executionContext, ExecutionStrategyParameters parameters, java.lang.Object result)
completeValue(ExecutionContext, ExecutionStrategyParameters)
for each value.executionContext
- contains the top level execution parametersparameters
- contains the parameters holding the fields to be executed and source objectresult
- the result to complete, raw resultFieldValueInfo
protected FieldValueInfo completeValueForList(ExecutionContext executionContext, ExecutionStrategyParameters parameters, java.lang.Iterable<java.lang.Object> iterableValues)
completeValue(ExecutionContext, ExecutionStrategyParameters)
for each value.executionContext
- contains the top level execution parametersparameters
- contains the parameters holding the fields to be executed and source objectiterableValues
- the values to complete, can't be nullFieldValueInfo
protected java.util.concurrent.CompletableFuture<ExecutionResult> completeValueForScalar(ExecutionContext executionContext, ExecutionStrategyParameters parameters, GraphQLScalarType scalarType, java.lang.Object result)
GraphQLScalarType
by asking that scalar type to coerce the object
into a valid valueexecutionContext
- contains the top level execution parametersparameters
- contains the parameters holding the fields to be executed and source objectscalarType
- the type of the scalarresult
- the result to be coercedExecutionResult
protected java.util.concurrent.CompletableFuture<ExecutionResult> completeValueForEnum(ExecutionContext executionContext, ExecutionStrategyParameters parameters, GraphQLEnumType enumType, java.lang.Object result)
GraphQLEnumType
by asking that enum type to coerce the object into a valid valueexecutionContext
- contains the top level execution parametersparameters
- contains the parameters holding the fields to be executed and source objectenumType
- the type of the enumresult
- the result to be coercedExecutionResult
protected java.util.concurrent.CompletableFuture<ExecutionResult> completeValueForObject(ExecutionContext executionContext, ExecutionStrategyParameters parameters, GraphQLObjectType resolvedObjectType, java.lang.Object result)
executionContext
- contains the top level execution parametersparameters
- contains the parameters holding the fields to be executed and source objectresolvedObjectType
- the resolved object typeresult
- the result to be coercedExecutionResult
protected java.lang.Object unboxPossibleOptional(java.lang.Object result)
result
- the incoming valueprotected java.lang.Iterable<java.lang.Object> toIterable(java.lang.Object result)
result
- the result objectjava.lang.ClassCastException
- if its not an Iterableprotected GraphQLObjectType resolveType(ExecutionContext executionContext, ExecutionStrategyParameters parameters, GraphQLType fieldType)
protected GraphQLObjectType resolveTypeForInterface(TypeResolutionParameters params)
GraphQLInterfaceType
into a specific GraphQLObjectType
so the object can be executed in terms of that typeparams
- the params needed for type resolutionGraphQLObjectType
protected GraphQLObjectType resolveTypeForUnion(TypeResolutionParameters params)
GraphQLUnionType
into a specific GraphQLObjectType
so the object can be executed in terms of that typeparams
- the params needed for type resolutionGraphQLObjectType
protected java.lang.Iterable<java.lang.Object> toIterable(ExecutionContext context, ExecutionStrategyParameters parameters, java.lang.Object result)
protected GraphQLFieldDefinition getFieldDef(ExecutionContext executionContext, ExecutionStrategyParameters parameters, Field field)
Field
executionContext
- contains the top level execution parametersparameters
- contains the parameters holding the fields to be executed and source objectfield
- the field to find the definition ofGraphQLFieldDefinition
protected GraphQLFieldDefinition getFieldDef(GraphQLSchema schema, GraphQLObjectType parentType, Field field)
Field
schema
- the schema in playparentType
- the parent type of the fieldfield
- the field to find the definition ofGraphQLFieldDefinition
protected void assertNonNullFieldPrecondition(NonNullableFieldWasNullException e) throws NonNullableFieldWasNullException
If a non nullable child field type actually resolves to a null value and the parent type is nullable then the parent must in fact become null so we use exceptions to indicate this special case. However if the parent is in fact a non nullable type itself then we need to bubble that upwards again until we get to the root in which case the result is meant to be null.
e
- this indicates that a null value was returned for a non null field, which needs to cause the parent field
to become null OR continue on as an exceptionNonNullableFieldWasNullException
- if a non null field resolves to a null valueprotected void assertNonNullFieldPrecondition(NonNullableFieldWasNullException e, java.util.concurrent.CompletableFuture<?> completableFuture) throws NonNullableFieldWasNullException
NonNullableFieldWasNullException
protected ExecutionResult handleNonNullException(ExecutionContext executionContext, java.util.concurrent.CompletableFuture<ExecutionResult> result, java.lang.Throwable e)
protected ExecutionTypeInfo fieldTypeInfo(ExecutionStrategyParameters parameters, GraphQLFieldDefinition fieldDefinition)
parameters
- contains the parameters holding the fields to be executed and source objectfieldDefinition
- the field definition to build type info forpublic static java.lang.String mkNameForPath(Field currentField)
public static java.lang.String mkNameForPath(java.util.List<Field> currentField)