Class ExecutionStrategy
- Direct Known Subclasses:
AbstractAsyncExecutionStrategy
,SubscriptionExecutionStrategy
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 it's 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://spec.graphql.org/October2021/#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.
-
Field Summary
FieldsModifier and TypeFieldDescriptionprotected final DataFetcherExceptionHandler
protected final ExecutionStepInfoFactory
protected final FieldCollector
-
Constructor Summary
ConstructorsModifierConstructorDescriptionprotected
The default execution strategy constructor uses theSimpleDataFetcherExceptionHandler
for data fetching errors.protected
ExecutionStrategy
(DataFetcherExceptionHandler dataFetcherExceptionHandler) The consumers of the execution strategy can pass in aDataFetcherExceptionHandler
to better decide what do when a data fetching error happens -
Method Summary
Modifier and TypeMethodDescriptionprotected void
See (...),protected void
assertNonNullFieldPrecondition
(NonNullableFieldWasNullException e, CompletableFuture<?> completableFuture) protected FieldValueInfo
completeField
(ExecutionContext executionContext, ExecutionStrategyParameters parameters, 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 Object
completeValueForEnum
(ExecutionContext executionContext, ExecutionStrategyParameters parameters, GraphQLEnumType enumType, Object result) Called to turn an object into an enum value according to theGraphQLEnumType
by asking that enum type to coerce the object into a valid valueprotected FieldValueInfo
completeValueForList
(ExecutionContext executionContext, ExecutionStrategyParameters parameters, Iterable<Object> iterableValues) Called to complete a list of value for a field based on a list type.protected FieldValueInfo
completeValueForList
(ExecutionContext executionContext, ExecutionStrategyParameters parameters, Object result) Called to complete a list of value for a field based on a list type.protected Object
completeValueForNull
(ExecutionStrategyParameters parameters) Called to complete a null value.protected Object
completeValueForObject
(ExecutionContext executionContext, ExecutionStrategyParameters parameters, GraphQLObjectType resolvedObjectType, Object result) Called to turn a java object value into an graphql object valueprotected Object
completeValueForScalar
(ExecutionContext executionContext, ExecutionStrategyParameters parameters, GraphQLScalarType scalarType, Object result) Called to turn an object into a scalar value according to theGraphQLScalarType
by asking that scalar type to coerce the object into a valid valueprotected ExecutionStepInfo
createExecutionStepInfo
(ExecutionContext executionContext, ExecutionStrategyParameters parameters, GraphQLFieldDefinition fieldDefinition, GraphQLObjectType fieldContainer) Builds the type info hierarchy for the current fieldabstract CompletableFuture
<ExecutionResult> execute
(ExecutionContext executionContext, ExecutionStrategyParameters parameters) This is the entry point to an execution strategy.protected Object
executeObject
(ExecutionContext executionContext, ExecutionStrategyParameters parameters) This is the re-entry point for an execution strategy when an object type needs to be resolved.protected Object
fetchField
(ExecutionContext executionContext, ExecutionStrategyParameters parameters) Called to fetch a value for a field from theDataFetcher
associated with the fieldGraphQLFieldDefinition
.protected GraphQLFieldDefinition
getFieldDef
(ExecutionContext executionContext, ExecutionStrategyParameters parameters, Field field) Called to discover the field definition give the current parameters and the ASTField
protected GraphQLFieldDefinition
getFieldDef
(GraphQLSchema schema, GraphQLObjectType parentType, Field field) Called to discover the field definition give the current parameters and the ASTField
protected Supplier
<ExecutableNormalizedField> getNormalizedField
(ExecutionContext executionContext, ExecutionStrategyParameters parameters, Supplier<ExecutionStepInfo> executionStepInfo) protected <T> CompletableFuture
<T> handleFetchingException
(DataFetchingEnvironment environment, ExecutionStrategyParameters parameters, Throwable e) protected ExecutionResult
handleNonNullException
(ExecutionContext executionContext, CompletableFuture<ExecutionResult> result, Throwable e) protected <T> void
handleValueException
(CompletableFuture<T> overallResult, Throwable e, ExecutionContext executionContext) static String
mkNameForPath
(MergedField mergedField) static String
mkNameForPath
(Field currentField) static String
mkNameForPath
(List<Field> currentField) protected Object
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) toIterable
(ExecutionContext context, ExecutionStrategyParameters parameters, Object result) protected Object
unboxPossibleDataFetcherResult
(ExecutionContext executionContext, ExecutionStrategyParameters parameters, Object result) If the data fetching returned aDataFetcherResult
then it can contain errors and new local context and hence it gets turned into aFetchedValue
but otherwise this method returns the unboxed value without the wrapper.
-
Field Details
-
fieldCollector
-
executionStepInfoFactory
-
dataFetcherExceptionHandler
-
-
Constructor Details
-
ExecutionStrategy
protected ExecutionStrategy()The default execution strategy constructor uses theSimpleDataFetcherExceptionHandler
for data fetching errors. -
ExecutionStrategy
The consumers of the execution strategy can pass in aDataFetcherExceptionHandler
to better decide what do when a data fetching error happens- Parameters:
dataFetcherExceptionHandler
- the callback invoked if an exception happens during data fetching
-
-
Method Details
-
mkNameForPath
-
mkNameForPath
-
mkNameForPath
-
execute
public abstract CompletableFuture<ExecutionResult> execute(ExecutionContext executionContext, ExecutionStrategyParameters parameters) throws NonNullableFieldWasNullException This is the entry point to an execution strategy. It will be passed the fields to execute and get values for.- Parameters:
executionContext
- contains the top level execution parametersparameters
- contains the parameters holding the fields to be executed and source object- Returns:
- a promise to an
ExecutionResult
- Throws:
NonNullableFieldWasNullException
- in the future if a non-null field resolves to a null value
-
executeObject
protected Object executeObject(ExecutionContext executionContext, ExecutionStrategyParameters parameters) throws NonNullableFieldWasNullException This is the re-entry point for an execution strategy when an object type needs to be resolved.- Parameters:
executionContext
- contains the top level execution parametersparameters
- contains the parameters holding the fields to be executed and source object- Returns:
- a
CompletableFuture
promise to a map of object field values or a materialized map of object field values - Throws:
NonNullableFieldWasNullException
- in theCompletableFuture
if a non-null field resolved to a null value
-
resolveFieldWithInfo
protected Object 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. This will call #fetchField followed by #completeField and the completedFieldValueInfo
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.- Parameters:
executionContext
- contains the top level execution parametersparameters
- contains the parameters holding the fields to be executed and source object- Returns:
- a
CompletableFuture
promise to aFieldValueInfo
or a materialisedFieldValueInfo
- Throws:
NonNullableFieldWasNullException
- in theFieldValueInfo.getFieldValueFuture()
future if a nonnull field resolves to a null value
-
fetchField
protected Object fetchField(ExecutionContext executionContext, ExecutionStrategyParameters parameters) Called to fetch a value for a field from theDataFetcher
associated with the fieldGraphQLFieldDefinition
.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.- Parameters:
executionContext
- contains the top level execution parametersparameters
- contains the parameters holding the fields to be executed and source object- Returns:
- a promise to a value object or the value itself. The value maybe a raw object OR a
FetchedValue
- Throws:
NonNullableFieldWasNullException
- in the future if a non-null field resolves to a null value
-
getNormalizedField
protected Supplier<ExecutableNormalizedField> getNormalizedField(ExecutionContext executionContext, ExecutionStrategyParameters parameters, Supplier<ExecutionStepInfo> executionStepInfo) -
unboxPossibleDataFetcherResult
protected Object unboxPossibleDataFetcherResult(ExecutionContext executionContext, ExecutionStrategyParameters parameters, Object result) If the data fetching returned aDataFetcherResult
then it can contain errors and new local context and hence it gets turned into aFetchedValue
but otherwise this method returns the unboxed value without the wrapper. This means its more efficient overall by default.- Parameters:
executionContext
- the execution context in playparameters
- the parameters in playresult
- the fetched raw object- Returns:
- an unboxed value which can be a FetchedValue or an Object
-
handleFetchingException
protected <T> CompletableFuture<T> handleFetchingException(DataFetchingEnvironment environment, ExecutionStrategyParameters parameters, Throwable e) -
completeField
protected FieldValueInfo completeField(ExecutionContext executionContext, ExecutionStrategyParameters parameters, Object fetchedValue) Called to complete a field based on the type of the field.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.- Parameters:
executionContext
- contains the top level execution parametersparameters
- contains the parameters holding the fields to be executed and source objectfetchedValue
- the fetched raw value or perhaps aFetchedValue
wrapper of that value- Returns:
- a
FieldValueInfo
- Throws:
NonNullableFieldWasNullException
- in theFieldValueInfo.getFieldValueFuture()
future if a nonnull field resolves to a null value
-
completeValue
protected FieldValueInfo completeValue(ExecutionContext executionContext, ExecutionStrategyParameters parameters) throws NonNullableFieldWasNullException Called to complete a value for a field based on the type of the field.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.- Parameters:
executionContext
- contains the top level execution parametersparameters
- contains the parameters holding the fields to be executed and source object- Returns:
- a
FieldValueInfo
- Throws:
NonNullableFieldWasNullException
- if a non null field resolves to a null value
-
completeValueForNull
Called to complete a null value.- Parameters:
parameters
- contains the parameters holding the fields to be executed and source object- Returns:
- a null value or a
CompletableFuture
exceptionally completed - Throws:
NonNullableFieldWasNullException
- inside theCompletableFuture
if a non-null field resolves to a null value
-
completeValueForList
protected FieldValueInfo completeValueForList(ExecutionContext executionContext, ExecutionStrategyParameters parameters, Object result) Called to complete a list of value for a field based on a list type. This iterates the values and callscompleteValue(ExecutionContext, ExecutionStrategyParameters)
for each value.- Parameters:
executionContext
- contains the top level execution parametersparameters
- contains the parameters holding the fields to be executed and source objectresult
- the result to complete, raw result- Returns:
- a
FieldValueInfo
-
completeValueForList
protected FieldValueInfo completeValueForList(ExecutionContext executionContext, ExecutionStrategyParameters parameters, Iterable<Object> iterableValues) Called to complete a list of value for a field based on a list type. This iterates the values and callscompleteValue(ExecutionContext, ExecutionStrategyParameters)
for each value.- Parameters:
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 null- Returns:
- a
FieldValueInfo
-
handleValueException
protected <T> void handleValueException(CompletableFuture<T> overallResult, Throwable e, ExecutionContext executionContext) -
completeValueForScalar
protected Object completeValueForScalar(ExecutionContext executionContext, ExecutionStrategyParameters parameters, GraphQLScalarType scalarType, Object result) Called to turn an object into a scalar value according to theGraphQLScalarType
by asking that scalar type to coerce the object into a valid value- Parameters:
executionContext
- 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 coerced- Returns:
- a materialized scalar value or exceptionally completed
CompletableFuture
if there is a problem
-
completeValueForEnum
protected Object completeValueForEnum(ExecutionContext executionContext, ExecutionStrategyParameters parameters, GraphQLEnumType enumType, Object result) Called to turn an object into an enum value according to theGraphQLEnumType
by asking that enum type to coerce the object into a valid value- Parameters:
executionContext
- 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 coerced- Returns:
- a materialized enum value or exceptionally completed
CompletableFuture
if there is a problem
-
completeValueForObject
protected Object completeValueForObject(ExecutionContext executionContext, ExecutionStrategyParameters parameters, GraphQLObjectType resolvedObjectType, Object result) Called to turn a java object value into an graphql object value- Parameters:
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 coerced- Returns:
- a
CompletableFuture
promise to a map of object field values or a materialized map of object field values
-
resolveType
protected GraphQLObjectType resolveType(ExecutionContext executionContext, ExecutionStrategyParameters parameters, GraphQLType fieldType) -
toIterable
protected Iterable<Object> toIterable(ExecutionContext context, ExecutionStrategyParameters parameters, Object result) -
getFieldDef
protected GraphQLFieldDefinition getFieldDef(ExecutionContext executionContext, ExecutionStrategyParameters parameters, Field field) Called to discover the field definition give the current parameters and the ASTField
- Parameters:
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 of- Returns:
- a
GraphQLFieldDefinition
-
getFieldDef
protected GraphQLFieldDefinition getFieldDef(GraphQLSchema schema, GraphQLObjectType parentType, Field field) Called to discover the field definition give the current parameters and the ASTField
- Parameters:
schema
- the schema in playparentType
- the parent type of the fieldfield
- the field to find the definition of- Returns:
- a
GraphQLFieldDefinition
-
assertNonNullFieldPrecondition
protected void assertNonNullFieldPrecondition(NonNullableFieldWasNullException e) throws NonNullableFieldWasNullException See (...),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.
- Parameters:
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 exception- Throws:
NonNullableFieldWasNullException
- if a non null field resolves to a null value
-
assertNonNullFieldPrecondition
protected void assertNonNullFieldPrecondition(NonNullableFieldWasNullException e, CompletableFuture<?> completableFuture) throws NonNullableFieldWasNullException - Throws:
NonNullableFieldWasNullException
-
handleNonNullException
protected ExecutionResult handleNonNullException(ExecutionContext executionContext, CompletableFuture<ExecutionResult> result, Throwable e) -
createExecutionStepInfo
protected ExecutionStepInfo createExecutionStepInfo(ExecutionContext executionContext, ExecutionStrategyParameters parameters, GraphQLFieldDefinition fieldDefinition, GraphQLObjectType fieldContainer) Builds the type info hierarchy for the current field- Parameters:
executionContext
- the execution context in playparameters
- contains the parameters holding the fields to be executed and source objectfieldDefinition
- the field definition to build type info forfieldContainer
- the field container- Returns:
- a new type info
-