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, FetchedValue)
and the other "completeXXX" methods.
The order of fields fetching and completion is up to the execution strategy. As the graphql specification https://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 CompletableFutures.
execute(ExecutionContext, ExecutionStrategyParameters) is the entry point of the execution strategy.
-
Field Summary
FieldsModifier and TypeFieldDescriptionprotected final DataFetcherExceptionHandlerprotected final ExecutionStepInfoFactoryprotected final FieldCollectorprivate static final org.slf4j.Loggerprivate static final org.slf4j.Loggerprivate final ResolveType -
Constructor Summary
ConstructorsModifierConstructorDescriptionprotectedThe default execution strategy constructor uses theSimpleDataFetcherExceptionHandlerfor data fetching errors.protectedExecutionStrategy(DataFetcherExceptionHandler dataFetcherExceptionHandler) The consumers of the execution strategy can pass in aDataFetcherExceptionHandlerto better decide what do when a data fetching error happens -
Method Summary
Modifier and TypeMethodDescriptionprivate voidaddExtensionsIfPresent(ExecutionContext executionContext, DataFetcherResult<?> dataFetcherResult) protected voidSee (...),protected voidassertNonNullFieldPrecondition(NonNullableFieldWasNullException e, CompletableFuture<?> completableFuture) private <T> CompletableFuture<T> asyncHandleException(DataFetcherExceptionHandler handler, DataFetcherExceptionHandlerParameters handlerParameters) protected FieldValueInfocompleteField(ExecutionContext executionContext, ExecutionStrategyParameters parameters, FetchedValue fetchedValue) Called to complete a field based on the type of the field.protected FieldValueInfocompleteValue(ExecutionContext executionContext, ExecutionStrategyParameters parameters) Called to complete a value for a field based on the type of the field.protected CompletableFuture<ExecutionResult> completeValueForEnum(ExecutionContext executionContext, ExecutionStrategyParameters parameters, GraphQLEnumType enumType, Object result) Called to turn an object into a enum value according to theGraphQLEnumTypeby asking that enum type to coerce the object into a valid valueprotected FieldValueInfocompleteValueForList(ExecutionContext executionContext, ExecutionStrategyParameters parameters, Iterable<Object> iterableValues) Called to complete a list of value for a field based on a list type.protected FieldValueInfocompleteValueForList(ExecutionContext executionContext, ExecutionStrategyParameters parameters, Object result) Called to complete a list of value for a field based on a list type.protected CompletableFuture<ExecutionResult> completeValueForNull(ExecutionContext executionContext, ExecutionStrategyParameters parameters) protected CompletableFuture<ExecutionResult> completeValueForObject(ExecutionContext executionContext, ExecutionStrategyParameters parameters, GraphQLObjectType resolvedObjectType, Object result) Called to turn a java object value into an graphql object valueprotected CompletableFuture<ExecutionResult> completeValueForScalar(ExecutionContext executionContext, ExecutionStrategyParameters parameters, GraphQLScalarType scalarType, Object result) Called to turn an object into a scalar value according to theGraphQLScalarTypeby asking that scalar type to coerce the object into a valid valueprotected ExecutionStepInfocreateExecutionStepInfo(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 CompletableFuture<FetchedValue> fetchField(ExecutionContext executionContext, ExecutionStrategyParameters parameters) Called to fetch a value for a field from theDataFetcherassociated with the fieldGraphQLFieldDefinition.private CompletableFuture<FetchedValue> fetchField(GraphQLFieldDefinition fieldDef, ExecutionContext executionContext, ExecutionStrategyParameters parameters) protected GraphQLFieldDefinitiongetFieldDef(ExecutionContext executionContext, ExecutionStrategyParameters parameters, Field field) Called to discover the field definition give the current parameters and the ASTFieldprotected GraphQLFieldDefinitiongetFieldDef(GraphQLSchema schema, GraphQLObjectType parentType, Field field) Called to discover the field definition give the current parameters and the ASTFieldprivate FieldValueInfogetFieldValueInfoForNull(ExecutionContext executionContext, ExecutionStrategyParameters parameters) Called to complete a null value.protected Supplier<ExecutableNormalizedField> getNormalizedField(ExecutionContext executionContext, ExecutionStrategyParameters parameters, Supplier<ExecutionStepInfo> executionStepInfo) private ObjecthandleCoercionProblem(ExecutionContext context, ExecutionStrategyParameters parameters, CoercingSerializeException e) protected <T> CompletableFuture<T> handleFetchingException(DataFetchingEnvironment environment, Throwable e) protected ExecutionResulthandleNonNullException(ExecutionContext executionContext, CompletableFuture<ExecutionResult> result, Throwable e) private voidhandleTypeMismatchProblem(ExecutionContext context, ExecutionStrategyParameters parameters, Object result) private voidhandleUnresolvedTypeProblem(ExecutionContext context, ExecutionStrategyParameters parameters, UnresolvedTypeException e) private CompletableFuture<Object> invokeDataFetcher(ExecutionContext executionContext, ExecutionStrategyParameters parameters, GraphQLFieldDefinition fieldDef, Supplier<DataFetchingEnvironment> dataFetchingEnvironment, DataFetcher<?> dataFetcher) static StringmkNameForPath(MergedField mergedField) static StringmkNameForPath(Field currentField) static StringmkNameForPath(List<Field> currentField) protected 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 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 GraphQLObjectTyperesolveType(ExecutionContext executionContext, ExecutionStrategyParameters parameters, GraphQLType fieldType) toIterable(ExecutionContext context, ExecutionStrategyParameters parameters, Object result) protected FetchedValueunboxPossibleDataFetcherResult(ExecutionContext executionContext, ExecutionStrategyParameters parameters, Object result)
-
Field Details
-
log
private static final org.slf4j.Logger log -
logNotSafe
private static final org.slf4j.Logger logNotSafe -
fieldCollector
-
executionStepInfoFactory
-
resolvedType
-
dataFetcherExceptionHandler
-
-
Constructor Details
-
ExecutionStrategy
protected ExecutionStrategy()The default execution strategy constructor uses theSimpleDataFetcherExceptionHandlerfor data fetching errors. -
ExecutionStrategy
The consumers of the execution strategy can pass in aDataFetcherExceptionHandlerto better decide what do when a data fetching error happens- Parameters:
dataFetcherExceptionHandler- the callback invoked if an exception happens during data fetching
-
-
Method Details
-
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
-
resolveField
protected 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. This will call #fetchField followed by #completeField and the completedExecutionResultis 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
Fieldvalues 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 an
ExecutionResult - Throws:
NonNullableFieldWasNullException- in the future if a non null field resolves to a null value
-
resolveFieldWithInfo
protected 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. This will call #fetchField followed by #completeField and the completedFieldValueInfois 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
Fieldvalues 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
FieldValueInfo - Throws:
NonNullableFieldWasNullException- in theFieldValueInfo.getFieldValue()future if a non null field resolves to a null value
-
fetchField
protected CompletableFuture<FetchedValue> fetchField(ExecutionContext executionContext, ExecutionStrategyParameters parameters) Called to fetch a value for a field from theDataFetcherassociated with the fieldGraphQLFieldDefinition.Graphql fragments mean that for any give logical field can have one or more
Fieldvalues 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 fetched object
- Throws:
NonNullableFieldWasNullException- in the future if a non null field resolves to a null value
-
fetchField
private CompletableFuture<FetchedValue> fetchField(GraphQLFieldDefinition fieldDef, ExecutionContext executionContext, ExecutionStrategyParameters parameters) -
invokeDataFetcher
private CompletableFuture<Object> invokeDataFetcher(ExecutionContext executionContext, ExecutionStrategyParameters parameters, GraphQLFieldDefinition fieldDef, Supplier<DataFetchingEnvironment> dataFetchingEnvironment, DataFetcher<?> dataFetcher) -
getNormalizedField
protected Supplier<ExecutableNormalizedField> getNormalizedField(ExecutionContext executionContext, ExecutionStrategyParameters parameters, Supplier<ExecutionStepInfo> executionStepInfo) -
unboxPossibleDataFetcherResult
protected FetchedValue unboxPossibleDataFetcherResult(ExecutionContext executionContext, ExecutionStrategyParameters parameters, Object result) -
addExtensionsIfPresent
private void addExtensionsIfPresent(ExecutionContext executionContext, DataFetcherResult<?> dataFetcherResult) -
handleFetchingException
protected <T> CompletableFuture<T> handleFetchingException(DataFetchingEnvironment environment, Throwable e) -
asyncHandleException
private <T> CompletableFuture<T> asyncHandleException(DataFetcherExceptionHandler handler, DataFetcherExceptionHandlerParameters handlerParameters) -
completeField
protected FieldValueInfo completeField(ExecutionContext executionContext, ExecutionStrategyParameters parameters, FetchedValue 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
Fieldvalues 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- Returns:
- a
FieldValueInfo - Throws:
NonNullableFieldWasNullException- in theFieldValueInfo.getFieldValue()future if a non null 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
Fieldvalues 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
-
handleUnresolvedTypeProblem
private void handleUnresolvedTypeProblem(ExecutionContext context, ExecutionStrategyParameters parameters, UnresolvedTypeException e) -
getFieldValueInfoForNull
private FieldValueInfo getFieldValueInfoForNull(ExecutionContext executionContext, ExecutionStrategyParameters parameters) Called to complete a null value.- 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
protected CompletableFuture<ExecutionResult> completeValueForNull(ExecutionContext executionContext, ExecutionStrategyParameters parameters) -
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
-
completeValueForScalar
protected CompletableFuture<ExecutionResult> completeValueForScalar(ExecutionContext executionContext, ExecutionStrategyParameters parameters, GraphQLScalarType scalarType, Object result) Called to turn an object into a scalar value according to theGraphQLScalarTypeby 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 promise to an
ExecutionResult
-
completeValueForEnum
protected CompletableFuture<ExecutionResult> completeValueForEnum(ExecutionContext executionContext, ExecutionStrategyParameters parameters, GraphQLEnumType enumType, Object result) Called to turn an object into a enum value according to theGraphQLEnumTypeby 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 promise to an
ExecutionResult
-
completeValueForObject
protected CompletableFuture<ExecutionResult> 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 promise to an
ExecutionResult
-
handleCoercionProblem
private Object handleCoercionProblem(ExecutionContext context, ExecutionStrategyParameters parameters, CoercingSerializeException e) -
resolveType
protected GraphQLObjectType resolveType(ExecutionContext executionContext, ExecutionStrategyParameters parameters, GraphQLType fieldType) -
toIterable
protected Iterable<Object> toIterable(ExecutionContext context, ExecutionStrategyParameters parameters, Object result) -
handleTypeMismatchProblem
private void handleTypeMismatchProblem(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
-
mkNameForPath
-
mkNameForPath
-
mkNameForPath
-