docs: protected CompletableFuture<FetchedValue> fetchField(ExecutionContext executionContext, ExecutionStrategyParameters parameters) {
          MergedField field = parameters.getField();
          GraphQLObjectType parentType = (GraphQLObjectType) parameters.getExecutionStepInfo().getUnwrappedNonNullType();
          GraphQLFieldDefinition fieldDef = getFieldDef(executionContext.getGraphQLSchema(), parentType, field.getSingleField());
  
          GraphQLCodeRegistry codeRegistry = executionContext.getGraphQLSchema().getCodeRegistry();
          Map<String, Object> argumentValues = valuesResolver.getArgumentValues(codeRegistry, fieldDef.getArguments(), field.getArguments(), executionContext.getVariables());
  
          GraphQLOutputType fieldType = fieldDef.getType();
          DataFetchingFieldSelectionSet fieldCollector = DataFetchingFieldSelectionSetImpl.newCollector(executionContext, fieldType, parameters.getField());
          ExecutionStepInfo executionStepInfo = createExecutionStepInfo(executionContext, parameters, fieldDef, parentType);
  
          DataFetchingEnvironment environment = newDataFetchingEnvironment(executionContext)
                  .source(parameters.getSource())
                  .localContext(parameters.getLocalContext())
                  .arguments(argumentValues)
                  .fieldDefinition(fieldDef)
                  .mergedField(parameters.getField())
                  .fieldType(fieldType)
                  .executionStepInfo(executionStepInfo)
                  .parentType(parentType)
                  .selectionSet(fieldCollector)
                  .build();
  
          DataFetcher dataFetcher = codeRegistry.getDataFetcher(parentType, fieldDef);
  
          Instrumentation instrumentation = executionContext.getInstrumentation();
  
          InstrumentationFieldFetchParameters instrumentationFieldFetchParams = new InstrumentationFieldFetchParameters(executionContext, fieldDef, environment, parameters, dataFetcher instanceof TrivialDataFetcher);
          InstrumentationContext<Object> fetchCtx = instrumentation.beginFieldFetch(instrumentationFieldFetchParams);
  
          CompletableFuture<Object> fetchedValue;
          dataFetcher = instrumentation.instrumentDataFetcher(dataFetcher, instrumentationFieldFetchParams);
          ExecutionId executionId = executionContext.getExecutionId();
          try {
              log.debug("'{}' fetching field '{}' using data fetcher '{}'...", executionId, executionStepInfo.getPath(), dataFetcher.getClass().getName());
              Object fetchedValueRaw = dataFetcher.get(environment);
              log.debug("'{}' field '{}' fetch returned '{}'", executionId, executionStepInfo.getPath(), fetchedValueRaw == null ? "null" : fetchedValueRaw.getClass().getName());
  
              fetchedValue = Async.toCompletableFuture(fetchedValueRaw);
          } catch (Exception e) {
              log.debug(String.format("'%s', field '%s' fetch threw exception", executionId, executionStepInfo.getPath()), e);
  
              fetchedValue = new CompletableFuture<>();
              fetchedValue.completeExceptionally(e);
          }
          fetchCtx.onDispatched(fetchedValue);
          return fetchedValue
                  .handle((result, exception) -> {
                      fetchCtx.onCompleted(result, exception);
                      if (exception != null) {
                          handleFetchingException(executionContext, parameters, environment, exception);
                          return null;
                      } else {
                          return result;
                      }
                  })
                  .thenApply(result -> unboxPossibleDataFetcherResult(executionContext, parameters, result));
      }