Skip to content

Commit a6508f4

Browse files
committed
Perform hasDataLoaderRegistrations check at runtime
Closes gh-1020
1 parent 9965c03 commit a6508f4

File tree

4 files changed

+54
-29
lines changed

4 files changed

+54
-29
lines changed

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -30,6 +30,17 @@
3030
*/
3131
public interface DataLoaderRegistrar {
3232

33+
34+
/**
35+
* Whether the registrar has any {@code DataLoader} registrations to make.
36+
* @since 1.2.8
37+
*/
38+
default boolean hasRegistrations() {
39+
DataLoaderRegistry registry = DataLoaderRegistry.newRegistry().build();
40+
registerDataLoaders(registry, GraphQLContext.newContext().build());
41+
return !registry.getDataLoaders().isEmpty();
42+
}
43+
3344
/**
3445
* Callback that provides access to the {@link DataLoaderRegistry} from the
3546
* the {@link graphql.ExecutionInput}.

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@ public <K, V> RegistrationSpec<K, V> forName(String name) {
8989
return new DefaultRegistrationSpec<>(name);
9090
}
9191

92+
@Override
93+
public boolean hasRegistrations() {
94+
return (!this.loaders.isEmpty() || !this.mappedLoaders.isEmpty());
95+
}
96+
9297
@Override
9398
public void registerDataLoaders(DataLoaderRegistry registry, GraphQLContext context) {
9499
BatchLoaderContextProvider contextProvider = () -> context;

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

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.springframework.graphql.ExecutionGraphQlResponse;
3434
import org.springframework.graphql.ExecutionGraphQlService;
3535
import org.springframework.graphql.support.DefaultExecutionGraphQlResponse;
36+
import org.springframework.lang.Nullable;
3637

3738
/**
3839
* {@link ExecutionGraphQlService} that uses a {@link GraphQlSource} to obtain a
@@ -51,7 +52,8 @@ public class DefaultExecutionGraphQlService implements ExecutionGraphQlService {
5152

5253
private final List<DataLoaderRegistrar> dataLoaderRegistrars = new ArrayList<>();
5354

54-
private boolean hasDataLoaderRegistrations;
55+
@Nullable
56+
private Boolean hasDataLoaderRegistrations;
5557

5658
private final boolean isDefaultExecutionIdProvider;
5759

@@ -70,13 +72,6 @@ public DefaultExecutionGraphQlService(GraphQlSource graphQlSource) {
7072
*/
7173
public void addDataLoaderRegistrar(DataLoaderRegistrar registrar) {
7274
this.dataLoaderRegistrars.add(registrar);
73-
this.hasDataLoaderRegistrations = (this.hasDataLoaderRegistrations || hasRegistrations(registrar));
74-
}
75-
76-
private static boolean hasRegistrations(DataLoaderRegistrar registrar) {
77-
DataLoaderRegistry registry = DataLoaderRegistry.newRegistry().build();
78-
registrar.registerDataLoaders(registry, GraphQLContext.newContext().build());
79-
return !registry.getDataLoaders().isEmpty();
8075
}
8176

8277

@@ -93,28 +88,41 @@ public final Mono<ExecutionGraphQlResponse> execute(ExecutionGraphQlRequest requ
9388
GraphQLContext graphQLContext = executionInput.getGraphQLContext();
9489
ContextSnapshot.captureFrom(contextView).updateContext(graphQLContext);
9590

96-
ExecutionInput updatedExecutionInput =
97-
(this.hasDataLoaderRegistrations ? registerDataLoaders(executionInput) : executionInput);
91+
ExecutionInput executionInputToUse = registerDataLoaders(executionInput);
9892

99-
return Mono.fromFuture(this.graphQlSource.graphQl().executeAsync(updatedExecutionInput))
100-
.map((result) -> new DefaultExecutionGraphQlResponse(updatedExecutionInput, result));
93+
return Mono.fromFuture(this.graphQlSource.graphQl().executeAsync(executionInputToUse))
94+
.map((result) -> new DefaultExecutionGraphQlResponse(executionInputToUse, result));
10195
});
10296
}
10397

10498
private ExecutionInput registerDataLoaders(ExecutionInput executionInput) {
105-
GraphQLContext graphQLContext = executionInput.getGraphQLContext();
106-
DataLoaderRegistry existingRegistry = executionInput.getDataLoaderRegistry();
107-
if (existingRegistry == DataLoaderDispatcherInstrumentationState.EMPTY_DATALOADER_REGISTRY) {
108-
DataLoaderRegistry newRegistry = DataLoaderRegistry.newRegistry().build();
109-
applyDataLoaderRegistrars(newRegistry, graphQLContext);
110-
executionInput = executionInput.transform((builder) -> builder.dataLoaderRegistry(newRegistry));
99+
if (this.hasDataLoaderRegistrations == null) {
100+
this.hasDataLoaderRegistrations = initHasDataLoaderRegistrations();
111101
}
112-
else {
113-
applyDataLoaderRegistrars(existingRegistry, graphQLContext);
102+
if (this.hasDataLoaderRegistrations) {
103+
GraphQLContext graphQLContext = executionInput.getGraphQLContext();
104+
DataLoaderRegistry existingRegistry = executionInput.getDataLoaderRegistry();
105+
if (existingRegistry == DataLoaderDispatcherInstrumentationState.EMPTY_DATALOADER_REGISTRY) {
106+
DataLoaderRegistry newRegistry = DataLoaderRegistry.newRegistry().build();
107+
applyDataLoaderRegistrars(newRegistry, graphQLContext);
108+
executionInput = executionInput.transform((builder) -> builder.dataLoaderRegistry(newRegistry));
109+
}
110+
else {
111+
applyDataLoaderRegistrars(existingRegistry, graphQLContext);
112+
}
114113
}
115114
return executionInput;
116115
}
117116

117+
private boolean initHasDataLoaderRegistrations() {
118+
for (DataLoaderRegistrar registrar : this.dataLoaderRegistrars) {
119+
if (registrar.hasRegistrations()) {
120+
return true;
121+
}
122+
}
123+
return false;
124+
}
125+
118126
private void applyDataLoaderRegistrars(DataLoaderRegistry registry, GraphQLContext graphQLContext) {
119127
this.dataLoaderRegistrars.forEach((registrar) -> registrar.registerDataLoaders(registry, graphQLContext));
120128
}

spring-graphql/src/test/java/org/springframework/graphql/execution/DefaultExecutionGraphQlServiceTests.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -41,26 +41,27 @@ public class DefaultExecutionGraphQlServiceTests {
4141

4242
@Test
4343
void customDataLoaderRegistry() {
44-
DefaultBatchLoaderRegistry batchLoaderRegistry = new DefaultBatchLoaderRegistry();
45-
batchLoaderRegistry.forTypePair(Book.class, Author.class)
46-
.registerBatchLoader((books, batchLoaderEnvironment) -> Flux.empty());
47-
4844
GraphQlSource graphQlSource = GraphQlSetup.schemaContent("type Query { greeting: String }")
4945
.queryFetcher("greeting", (env) -> "hi")
5046
.toGraphQlSource();
5147

48+
BatchLoaderRegistry batchLoaderRegistry = new DefaultBatchLoaderRegistry();
5249
DefaultExecutionGraphQlService graphQlService = new DefaultExecutionGraphQlService(graphQlSource);
5350
graphQlService.addDataLoaderRegistrar(batchLoaderRegistry);
5451

55-
DataLoaderRegistry myRegistry = new DataLoaderRegistry();
52+
// gh-1020: register loader after adding the registry to DefaultExecutionGraphQlService
53+
batchLoaderRegistry.forTypePair(Book.class, Author.class)
54+
.registerBatchLoader((books, batchLoaderEnvironment) -> Flux.empty());
55+
56+
DataLoaderRegistry dataLoaderRegistry = new DataLoaderRegistry();
5657

5758
ExecutionGraphQlRequest request = TestExecutionRequest.forDocument("{ greeting }");
58-
request.configureExecutionInput((input, builder) -> builder.dataLoaderRegistry(myRegistry).build());
59+
request.configureExecutionInput((input, builder) -> builder.dataLoaderRegistry(dataLoaderRegistry).build());
5960

6061
ExecutionGraphQlResponse response = graphQlService.execute(request).block();
6162
Map<?, ?> data = response.getExecutionResult().getData();
6263
assertThat(data).isEqualTo(Map.of("greeting", "hi"));
63-
assertThat(myRegistry.getDataLoaders()).hasSize(1);
64+
assertThat(dataLoaderRegistry.getDataLoaders()).hasSize(1);
6465
}
6566

6667
}

0 commit comments

Comments
 (0)