Skip to content

Commit 4dd13ed

Browse files
committed
Fix issue with auto-registration for non-null types
Closes gh-418
1 parent 65cd5bf commit 4dd13ed

File tree

4 files changed

+70
-16
lines changed

4 files changed

+70
-16
lines changed

spring-graphql/src/main/java/org/springframework/graphql/data/query/AutoRegistrationRuntimeWiringConfigurer.java

Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,13 @@
2424
import graphql.schema.DataFetcher;
2525
import graphql.schema.GraphQLList;
2626
import graphql.schema.GraphQLNamedOutputType;
27+
import graphql.schema.GraphQLNonNull;
2728
import graphql.schema.GraphQLType;
2829
import graphql.schema.idl.FieldWiringEnvironment;
2930
import graphql.schema.idl.RuntimeWiring;
3031
import graphql.schema.idl.WiringFactory;
32+
import org.apache.commons.logging.Log;
33+
import org.apache.commons.logging.LogFactory;
3134

3235
import org.springframework.graphql.execution.RuntimeWiringConfigurer;
3336
import org.springframework.lang.Nullable;
@@ -43,10 +46,19 @@
4346
*/
4447
class AutoRegistrationRuntimeWiringConfigurer implements RuntimeWiringConfigurer {
4548

49+
private final static Log logger = LogFactory.getLog(AutoRegistrationRuntimeWiringConfigurer.class);
50+
51+
4652
private final Map<String, Function<Boolean, DataFetcher<?>>> dataFetcherFactories;
4753

4854

49-
public AutoRegistrationRuntimeWiringConfigurer(
55+
/**
56+
* Constructor with a Map of GraphQL type names for which auto-registration
57+
* can be performed.
58+
* @param dataFetcherFactories Map with GraphQL type names as keys, and
59+
* functions to create a corresponding {@link DataFetcher} as values.
60+
*/
61+
AutoRegistrationRuntimeWiringConfigurer(
5062
Map<String, Function<Boolean, DataFetcher<?>>> dataFetcherFactories) {
5163

5264
this.dataFetcherFactories = dataFetcherFactories;
@@ -84,16 +96,32 @@ public boolean providesDataFetcher(FieldWiringEnvironment environment) {
8496
return false;
8597
}
8698

99+
String outputTypeName = getOutputTypeName(environment);
100+
101+
boolean result = (outputTypeName != null &&
102+
dataFetcherFactories.containsKey(outputTypeName) &&
103+
!hasDataFetcherFor(environment.getFieldDefinition()));
104+
105+
if (!result) {
106+
// This may be called multiples times on success, so log only rejections from here
107+
logTraceMessage(environment, outputTypeName, false);
108+
}
109+
110+
return result;
111+
}
112+
113+
@Nullable
114+
private String getOutputTypeName(FieldWiringEnvironment environment) {
87115
GraphQLType outputType = (environment.getFieldType() instanceof GraphQLList ?
88116
((GraphQLList) environment.getFieldType()).getWrappedType() :
89117
environment.getFieldType());
90118

91-
String outputTypeName = (outputType instanceof GraphQLNamedOutputType ?
92-
((GraphQLNamedOutputType) outputType).getName() : null);
119+
if (outputType instanceof GraphQLNonNull) {
120+
outputType = ((GraphQLNonNull) outputType).getWrappedType();
121+
}
93122

94-
return (outputTypeName != null &&
95-
dataFetcherFactories.containsKey(outputTypeName) &&
96-
!hasDataFetcherFor(environment.getFieldDefinition()));
123+
return (outputType instanceof GraphQLNamedOutputType ?
124+
((GraphQLNamedOutputType) outputType).getName() : null);
97125
}
98126

99127
private boolean hasDataFetcherFor(FieldDefinition fieldDefinition) {
@@ -104,18 +132,27 @@ private boolean hasDataFetcherFor(FieldDefinition fieldDefinition) {
104132
return this.existingQueryDataFetcherPredicate.test(fieldDefinition.getName());
105133
}
106134

135+
private void logTraceMessage(
136+
FieldWiringEnvironment environment, @Nullable String outputTypeName, boolean match) {
137+
138+
if (logger.isTraceEnabled()) {
139+
String query = environment.getFieldDefinition().getName();
140+
logger.trace((match ? "Matched" : "Skipped") +
141+
" output typeName " + (outputTypeName != null ? "'" + outputTypeName + "'" : "null") +
142+
" for query '" + query + "'");
143+
}
144+
}
145+
107146
@Override
108147
public DataFetcher<?> getDataFetcher(FieldWiringEnvironment environment) {
109-
return environment.getFieldType() instanceof GraphQLList ?
110-
initDataFetcher(((GraphQLList) environment.getFieldType()).getWrappedType(), false) :
111-
initDataFetcher(environment.getFieldType(), true);
112-
}
113148

114-
private DataFetcher<?> initDataFetcher(GraphQLType type, boolean single) {
115-
Assert.isInstanceOf(GraphQLNamedOutputType.class, type);
116-
String typeName = ((GraphQLNamedOutputType) type).getName();
117-
Function<Boolean, DataFetcher<?>> factory = dataFetcherFactories.get(typeName);
118-
Assert.notNull(factory, "Expected DataFetcher factory");
149+
String outputTypeName = getOutputTypeName(environment);
150+
logTraceMessage(environment, outputTypeName, true);
151+
152+
Function<Boolean, DataFetcher<?>> factory = dataFetcherFactories.get(outputTypeName);
153+
Assert.notNull(factory, "Expected DataFetcher factory for typeName '" + outputTypeName + "'");
154+
155+
boolean single = !(environment.getFieldType() instanceof GraphQLList);
119156
return factory.apply(single);
120157
}
121158

spring-graphql/src/main/java/org/springframework/graphql/data/query/QueryByExampleDataFetcher.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
import graphql.schema.DataFetchingEnvironment;
2828
import graphql.schema.DataFetchingFieldSelectionSet;
2929
import graphql.schema.GraphQLTypeVisitor;
30+
import org.apache.commons.logging.Log;
31+
import org.apache.commons.logging.LogFactory;
3032
import reactor.core.publisher.Flux;
3133
import reactor.core.publisher.Mono;
3234

@@ -90,6 +92,9 @@
9092
*/
9193
public abstract class QueryByExampleDataFetcher<T> {
9294

95+
private final static Log logger = LogFactory.getLog(QueryByExampleDataFetcher.class);
96+
97+
9398
private final TypeInformation<T> domainType;
9499

95100
private final GraphQlArgumentBinder argumentBinder;
@@ -185,6 +190,10 @@ public static RuntimeWiringConfigurer autoRegistrationConfigurer(
185190
}
186191
}
187192

193+
if (logger.isTraceEnabled()) {
194+
logger.trace("Auto-registration candidate typeNames " + factories.keySet());
195+
}
196+
188197
return new AutoRegistrationRuntimeWiringConfigurer(factories);
189198
}
190199

spring-graphql/src/main/java/org/springframework/graphql/data/query/QuerydslDataFetcher.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
import graphql.schema.DataFetchingEnvironment;
3030
import graphql.schema.DataFetchingFieldSelectionSet;
3131
import graphql.schema.GraphQLTypeVisitor;
32+
import org.apache.commons.logging.Log;
33+
import org.apache.commons.logging.LogFactory;
3234
import reactor.core.publisher.Flux;
3335
import reactor.core.publisher.Mono;
3436

@@ -97,6 +99,8 @@
9799
*/
98100
public abstract class QuerydslDataFetcher<T> {
99101

102+
private final static Log logger = LogFactory.getLog(QueryByExampleDataFetcher.class);
103+
100104
private static final QuerydslPredicateBuilder BUILDER = new QuerydslPredicateBuilder(
101105
DefaultConversionService.getSharedInstance(), SimpleEntityPathResolver.INSTANCE);
102106

@@ -215,6 +219,10 @@ public static RuntimeWiringConfigurer autoRegistrationConfigurer(
215219
}
216220
}
217221

222+
if (logger.isTraceEnabled()) {
223+
logger.trace("Auto-registration candidate typeNames " + factories.keySet());
224+
}
225+
218226
return new AutoRegistrationRuntimeWiringConfigurer(factories);
219227
}
220228

spring-graphql/src/test/resources/books/schema.graphqls

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
type Query {
22
bookById(id: ID): Book
33
booksById(id: [ID]): [Book]
4-
books(id: ID, name: String, author: String): [Book]
4+
books(id: ID, name: String, author: String): [Book!]
55
booksByCriteria(criteria:BookCriteria): [Book]
66
booksByProjectedArguments(name: String, author: String): [Book]
77
booksByProjectedCriteria(criteria:BookCriteria): [Book]

0 commit comments

Comments
 (0)