Skip to content

Commit 800cf8f

Browse files
committed
Add TypeVisitorHelper
See gh-722
1 parent 729d538 commit 800cf8f

File tree

4 files changed

+118
-17
lines changed

4 files changed

+118
-17
lines changed

spring-graphql/src/main/java/org/springframework/graphql/execution/AbstractGraphQlSourceBuilder.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
package org.springframework.graphql.execution;
1818

1919
import java.util.ArrayList;
20-
import java.util.Collections;
20+
import java.util.HashMap;
2121
import java.util.List;
2222
import java.util.Map;
2323
import java.util.function.Consumer;
@@ -132,17 +132,19 @@ private GraphQLSchema applyTypeVisitorsToTransformSchema(GraphQLSchema schema) {
132132
}
133133

134134
private GraphQLSchema applyTypeVisitors(GraphQLSchema schema) {
135-
GraphQLTypeVisitor visitor = ContextDataFetcherDecorator.createVisitor(schema, this.subscriptionExceptionResolvers);
136-
List<GraphQLTypeVisitor> visitors = new ArrayList<>(this.typeVisitors);
137-
visitors.add(visitor);
138135

139-
GraphQLCodeRegistry.Builder codeRegistry = GraphQLCodeRegistry.newCodeRegistry(schema.getCodeRegistry());
140-
Map<Class<?>, Object> vars = Collections.singletonMap(GraphQLCodeRegistry.Builder.class, codeRegistry);
136+
GraphQLCodeRegistry.Builder outputCodeRegistry =
137+
GraphQLCodeRegistry.newCodeRegistry(schema.getCodeRegistry());
141138

142-
SchemaTraverser traverser = new SchemaTraverser();
143-
traverser.depthFirstFullSchema(visitors, schema, vars);
139+
Map<Class<?>, Object> vars = new HashMap<>(2);
140+
vars.put(GraphQLCodeRegistry.Builder.class, outputCodeRegistry);
141+
vars.put(TypeVisitorHelper.class, TypeVisitorHelper.create(schema));
144142

145-
return schema.transformWithoutTypes(builder -> builder.codeRegistry(codeRegistry));
143+
List<GraphQLTypeVisitor> visitorsToUse = new ArrayList<>(this.typeVisitors);
144+
visitorsToUse.add(ContextDataFetcherDecorator.createVisitor(this.subscriptionExceptionResolvers));
145+
146+
new SchemaTraverser().depthFirstFullSchema(visitorsToUse, schema, vars);
147+
return schema.transformWithoutTypes(builder -> builder.codeRegistry(outputCodeRegistry));
146148
}
147149

148150

spring-graphql/src/main/java/org/springframework/graphql/execution/ContextDataFetcherDecorator.java

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@
2525
import graphql.schema.GraphQLCodeRegistry;
2626
import graphql.schema.GraphQLFieldDefinition;
2727
import graphql.schema.GraphQLFieldsContainer;
28-
import graphql.schema.GraphQLObjectType;
29-
import graphql.schema.GraphQLSchema;
3028
import graphql.schema.GraphQLSchemaElement;
3129
import graphql.schema.GraphQLTypeVisitor;
3230
import graphql.schema.GraphQLTypeVisitorStub;
@@ -114,25 +112,24 @@ public Object get(DataFetchingEnvironment environment) throws Exception {
114112
* Static factory method to create {@link GraphQLTypeVisitor} that wraps
115113
* data fetchers with the {@link ContextDataFetcherDecorator}.
116114
*/
117-
static GraphQLTypeVisitor createVisitor(
118-
GraphQLSchema schema, List<SubscriptionExceptionResolver> resolvers) {
119-
120-
GraphQLObjectType subscriptionType = schema.getSubscriptionType();
121-
String subscriptionTypeName = (subscriptionType != null ? subscriptionType.getName() : null);
115+
static GraphQLTypeVisitor createVisitor(List<SubscriptionExceptionResolver> resolvers) {
122116

123117
SubscriptionExceptionResolver exceptionResolver = new CompositeSubscriptionExceptionResolver(resolvers);
124118

125119
return new GraphQLTypeVisitorStub() {
120+
126121
@Override
127122
public TraversalControl visitGraphQLFieldDefinition(
128123
GraphQLFieldDefinition fieldDefinition, TraverserContext<GraphQLSchemaElement> context) {
129124

125+
TypeVisitorHelper visitorHelper = context.getVarFromParents(TypeVisitorHelper.class);
130126
GraphQLCodeRegistry.Builder codeRegistry = context.getVarFromParents(GraphQLCodeRegistry.Builder.class);
127+
131128
GraphQLFieldsContainer parent = (GraphQLFieldsContainer) context.getParentNode();
132129
DataFetcher<?> dataFetcher = codeRegistry.getDataFetcher(parent, fieldDefinition);
133130

134131
if (applyDecorator(dataFetcher)) {
135-
boolean handlesSubscription = parent.getName().equals(subscriptionTypeName);
132+
boolean handlesSubscription = visitorHelper.isSubscriptionType(parent);
136133
dataFetcher = new ContextDataFetcherDecorator(dataFetcher, handlesSubscription, exceptionResolver);
137134
codeRegistry.dataFetcher(parent, fieldDefinition, dataFetcher);
138135
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright 2002-2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.graphql.execution;
18+
19+
import graphql.schema.GraphQLNamedType;
20+
import graphql.schema.GraphQLObjectType;
21+
import graphql.schema.GraphQLSchema;
22+
23+
import org.springframework.lang.Nullable;
24+
25+
/**
26+
* Default implementation of {@link TypeVisitorHelper} that performs checks
27+
* against {@link GraphQLSchema}.
28+
*
29+
* @author Rossen Stoyanchev
30+
* @since 1.2.1
31+
*/
32+
final class DefaultTypeVisitorHelper implements TypeVisitorHelper {
33+
34+
@Nullable
35+
private final String subscriptionTypeName;
36+
37+
38+
/**
39+
* Package private constructor
40+
*/
41+
DefaultTypeVisitorHelper(GraphQLSchema schema) {
42+
GraphQLObjectType subscriptionType = schema.getSubscriptionType();
43+
this.subscriptionTypeName = (subscriptionType != null ? subscriptionType.getName() : null);
44+
}
45+
46+
47+
/**
48+
* Whether the given type is the subscription type.
49+
*/
50+
@Override
51+
public boolean isSubscriptionType(GraphQLNamedType type) {
52+
return (type.getName().equals(this.subscriptionTypeName));
53+
}
54+
55+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright 2002-2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.graphql.execution;
18+
19+
import java.util.List;
20+
21+
import graphql.schema.GraphQLNamedType;
22+
import graphql.schema.GraphQLSchema;
23+
24+
/**
25+
* Helper for {@link graphql.schema.GraphQLTypeVisitor}s registered via
26+
* {@link GraphQlSource.Builder#typeVisitors(List)} that is exposed as a
27+
* variable in {@link graphql.util.TraverserContext}.
28+
*
29+
* @author Rossen Stoyanchev
30+
* @since 1.2.1
31+
*/
32+
public interface TypeVisitorHelper {
33+
34+
/**
35+
* Whether the given type is the subscription type.
36+
*/
37+
boolean isSubscriptionType(GraphQLNamedType type);
38+
39+
40+
/**
41+
* Create an instance with the given {@link GraphQLSchema}.
42+
*/
43+
static TypeVisitorHelper create(GraphQLSchema schema) {
44+
return new DefaultTypeVisitorHelper(schema);
45+
}
46+
47+
}

0 commit comments

Comments
 (0)