Skip to content

Commit d4b2266

Browse files
committed
Schema inspection handles List from Subscription
Normally a multivalue Publisher is collected to a List, so we can treat it as a match for a List field. For subscriptions, however, such a Publisher is left as an infinite stream, and we should not treat as a match for a List, but rather expect it to be a stream of List items. Discovered while working on gh-674, which is closely related.
1 parent 133b406 commit d4b2266

File tree

2 files changed

+17
-15
lines changed

2 files changed

+17
-15
lines changed

Diff for: spring-graphql/src/main/java/org/springframework/graphql/execution/SchemaMappingInspector.java

+12-10
Original file line numberDiff line numberDiff line change
@@ -112,14 +112,14 @@ private SchemaMappingInspector(GraphQLSchema schema, RuntimeWiring runtimeWiring
112112
*/
113113
public Report inspect() {
114114

115-
inspectSchemaType(this.schema.getQueryType(), null);
115+
inspectSchemaType(this.schema.getQueryType(), null, false);
116116

117117
if (this.schema.isSupportingMutations()) {
118-
inspectSchemaType(this.schema.getMutationType(), null);
118+
inspectSchemaType(this.schema.getMutationType(), null, false);
119119
}
120120

121121
if (this.schema.isSupportingSubscriptions()) {
122-
inspectSchemaType(this.schema.getSubscriptionType(), null);
122+
inspectSchemaType(this.schema.getSubscriptionType(), null, false);
123123
}
124124

125125
inspectDataFetcherRegistrations();
@@ -128,7 +128,7 @@ public Report inspect() {
128128
}
129129

130130
@SuppressWarnings("rawtypes")
131-
private void inspectSchemaType(GraphQLType type, @Nullable ResolvableType resolvableType) {
131+
private void inspectSchemaType(GraphQLType type, @Nullable ResolvableType resolvableType, boolean subscription) {
132132
Assert.notNull(type, "No GraphQLType");
133133

134134
type = unwrapNonNull(type);
@@ -138,7 +138,7 @@ private void inspectSchemaType(GraphQLType type, @Nullable ResolvableType resolv
138138
}
139139
else if (type instanceof GraphQLList listType) {
140140
type = unwrapNonNull(listType.getWrappedType());
141-
resolvableType = nestForList(resolvableType, type);
141+
resolvableType = nestForList(resolvableType, type, subscription);
142142
}
143143
else {
144144
resolvableType = (resolvableType != null ? nestIfReactive(resolvableType) : null);
@@ -177,7 +177,9 @@ else if (resolvableType != null && resolvableType.resolve(Object.class) == Objec
177177
if (dataFetcherMap.containsKey(fieldName)) {
178178
DataFetcher<?> fetcher = dataFetcherMap.get(fieldName);
179179
if (fetcher instanceof SelfDescribingDataFetcher<?> selfDescribingDataFetcher) {
180-
inspectSchemaType(field.getType(), selfDescribingDataFetcher.getReturnType());
180+
inspectSchemaType(
181+
field.getType(), selfDescribingDataFetcher.getReturnType(),
182+
(type == this.schema.getSubscriptionType()));
181183
}
182184
else if (isNotScalarOrEnumType(field.getType())) {
183185
if (logger.isDebugEnabled()) {
@@ -228,15 +230,15 @@ private ResolvableType nestIfReactive(ResolvableType type) {
228230
return type;
229231
}
230232

231-
private ResolvableType nestForList(@Nullable ResolvableType type, GraphQLType graphQlType) {
233+
private ResolvableType nestForList(@Nullable ResolvableType type, GraphQLType graphQlType, boolean subscription) {
232234
Assert.state(type != null, "No Java type for " + getTypeName(graphQlType));
233235
ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(type.resolve(Object.class));
234236
if (adapter != null) {
235-
if (adapter.isMultiValue()) {
236-
return type.getNested(2);
237-
}
238237
Assert.state(!adapter.isNoValue(), "Expected List compatible type: " + type);
239238
type = type.getNested(2);
239+
if (adapter.isMultiValue() && !subscription) {
240+
return type;
241+
}
240242
}
241243
Assert.state(type.isArray() || type.hasGenerics(), "Expected List compatible type: " + type);
242244
return type.getNested(2);

Diff for: spring-graphql/src/test/java/org/springframework/graphql/execution/SchemaMappingInspectorTests.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ void reportContainsUnmappedSubscription() {
219219
greeting: String
220220
}
221221
type Subscription {
222-
bookSearch(author: String) : Book!
222+
bookSearch(author: String) : [Book!]!
223223
}
224224
225225
type Book {
@@ -238,7 +238,7 @@ void reportIsEmptyWhenSubscriptionIsMapped() {
238238
greeting: String
239239
}
240240
type Subscription {
241-
bookSearch(author: String) : Book!
241+
bookSearch(author: String) : [Book!]!
242242
}
243243
244244
type Book {
@@ -259,7 +259,7 @@ void reportWorksForSubscriptionWithExtensionType() {
259259
type Subscription {
260260
}
261261
extend type Subscription {
262-
bookSearch(author: String) : Book!
262+
bookSearch(author: String) : [Book!]!
263263
}
264264
type Book {
265265
id: ID
@@ -493,7 +493,7 @@ void reportUnmappedField() {
493493
createBook: Book
494494
}
495495
type Subscription {
496-
bookSearch(author: String) : Book!
496+
bookSearch(author: String) : [Book!]!
497497
}
498498
type Book {
499499
id: ID
@@ -598,7 +598,7 @@ public Book createBook() {
598598
}
599599

600600
@SubscriptionMapping
601-
public Flux<Book> bookSearch(@Argument String author) {
601+
public Flux<List<Book>> bookSearch(@Argument String author) {
602602
return Flux.empty();
603603
}
604604
}

0 commit comments

Comments
 (0)