Apply type visitors via SchemaTraverser

Transforming the schema can be expensive and should be separated from
use cases where type visitors don't need to change the schema.

For now we'll provide read-only traversal only. Separately we can
provide an option for schema transformation when it becomes necessary.
This commit is contained in:
Rossen Stoyanchev
2021-07-20 16:49:32 +01:00
parent a316c0411a
commit f0ce9424bd
2 changed files with 25 additions and 9 deletions

View File

@@ -20,15 +20,18 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import graphql.GraphQL;
import graphql.execution.instrumentation.ChainedInstrumentation;
import graphql.execution.instrumentation.Instrumentation;
import graphql.schema.GraphQLCodeRegistry;
import graphql.schema.GraphQLSchema;
import graphql.schema.GraphQLTypeVisitor;
import graphql.schema.SchemaTransformer;
import graphql.schema.SchemaTraverser;
import graphql.schema.idl.RuntimeWiring;
import graphql.schema.idl.SchemaGenerator;
import graphql.schema.idl.SchemaParser;
@@ -104,18 +107,14 @@ class DefaultGraphQlSourceBuilder implements GraphQlSource.Builder {
.orElseThrow(() -> new IllegalArgumentException("'schemaResources' should not be empty"));
GraphQLSchema schema = new SchemaGenerator().makeExecutableSchema(registry, this.runtimeWiring);
for (GraphQLTypeVisitor visitor : this.typeVisitors) {
schema = SchemaTransformer.transformSchema(schema, visitor);
}
// This comes last, wraps other DataFetcher's
schema = SchemaTransformer.transformSchema(schema, ContextDataFetcherDecorator.TYPE_VISITOR);
schema = applyTypeVisitors(schema);
GraphQL.Builder builder = GraphQL.newGraphQL(schema);
builder.defaultDataFetcherExceptionHandler(new ExceptionResolversExceptionHandler(this.exceptionResolvers));
if (!this.instrumentations.isEmpty()) {
builder = builder.instrumentation(new ChainedInstrumentation(this.instrumentations));
}
this.graphQlConfigurers.accept(builder);
GraphQL graphQl = builder.build();
@@ -135,6 +134,21 @@ class DefaultGraphQlSourceBuilder implements GraphQlSource.Builder {
}
}
private GraphQLSchema applyTypeVisitors(GraphQLSchema schema) {
List<GraphQLTypeVisitor> visitors = new ArrayList<>(this.typeVisitors);
visitors.add(ContextDataFetcherDecorator.TYPE_VISITOR);
GraphQLCodeRegistry.Builder builder = GraphQLCodeRegistry.newCodeRegistry(schema.getCodeRegistry());
Map<Class<?>, Object> vars = Collections.singletonMap(GraphQLCodeRegistry.Builder.class, builder);
SchemaTraverser traverser = new SchemaTraverser();
traverser.depthFirstFullSchema(visitors, schema, vars);
return GraphQLSchema.newSchema(schema).codeRegistry(builder.build()).build();
}
/**
* GraphQlSource that returns the built GraphQL instance and its schema.
*/

View File

@@ -96,8 +96,10 @@ public interface GraphQlSource {
Builder exceptionResolvers(List<DataFetcherExceptionResolver> resolvers);
/**
* Add {@link GraphQLTypeVisitor}'s to transform the underlying
* {@link graphql.schema.GraphQLSchema} with.
* Add {@link GraphQLTypeVisitor}s to visit all element of the created
* {@link graphql.schema.GraphQLSchema}.
* <p><strong>Note:</strong> Visitors are applied via
* {@link graphql.schema.SchemaTraverser} and cannot change the schema.
* @param typeVisitors the type visitors
* @return the current builder
* @see graphql.schema.SchemaTransformer#transformSchema(GraphQLSchema,