Skip to content

Commit 627d4f4

Browse files
committed
CursorStrategy is now also detected as a bean
See gh-620
1 parent fd46e0d commit 627d4f4

File tree

2 files changed

+53
-53
lines changed

2 files changed

+53
-53
lines changed

spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerConfigurer.java

+44-39
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
import org.springframework.core.ResolvableType;
5959
import org.springframework.core.annotation.AnnotatedElementUtils;
6060
import org.springframework.core.convert.ConversionService;
61+
import org.springframework.data.domain.ScrollPosition;
6162
import org.springframework.format.FormatterRegistrar;
6263
import org.springframework.format.support.DefaultFormattingConversionService;
6364
import org.springframework.format.support.FormattingConversionService;
@@ -82,14 +83,27 @@
8283
import org.springframework.validation.DataBinder;
8384

8485
/**
85-
* {@link RuntimeWiringConfigurer} that detects {@link SchemaMapping @SchemaMapping}
86-
* annotated handler methods in {@link Controller @Controller} classes and
87-
* registers them as {@link DataFetcher}s.
86+
* {@link RuntimeWiringConfigurer} that finds {@link SchemaMapping @SchemaMapping}
87+
* annotated handler methods in {@link Controller @Controller} classes declared in
88+
* Spring configuration, and registers them as {@link DataFetcher}s.
8889
*
8990
* <p>In addition to initializing a {@link RuntimeWiring.Builder}, this class, also
9091
* provides an option to {@link #configure(GraphQLCodeRegistry.Builder) configure}
9192
* data fetchers on a {@link GraphQLCodeRegistry.Builder}.
9293
*
94+
* <p>This class detects the following strategies in Spring configuration,
95+
* expecting to find a single, unique bean of that type:
96+
* <ul>
97+
* <li>{@link CursorStrategy} -- if Spring Data is present, and the strategy
98+
* supports {@code ScrollPosition}, then {@link ScrollSubrangeMethodArgumentResolver}
99+
* is configured for use. If not, then {@link SubrangeMethodArgumentResolver}
100+
* is added instead.
101+
* <li>{@link SortStrategy} -- if present, then {@link SortMethodArgumentResolver}
102+
* is configured for use.
103+
* </ul>
104+
*
105+
*
106+
*
93107
* @author Rossen Stoyanchev
94108
* @author Brian Clozel
95109
* @since 1.0.0
@@ -125,9 +139,6 @@ public class AnnotatedControllerConfigurer implements ApplicationContextAware, I
125139

126140
private final FormattingConversionService conversionService = new DefaultFormattingConversionService();
127141

128-
@Nullable
129-
private CursorStrategy<?> cursorStrategy;
130-
131142
private final List<HandlerMethodArgumentResolver> customArgumentResolvers = new ArrayList<>(8);
132143

133144
@Nullable
@@ -156,21 +167,6 @@ public void addFormatterRegistrar(FormatterRegistrar registrar) {
156167
registrar.registerFormatters(this.conversionService);
157168
}
158169

159-
/**
160-
* Configure a {@link CursorStrategy} to handle pagination requests, which
161-
* results in one of the following:
162-
* <ul>
163-
* <li>If Spring Data is present, and the strategy supports {@code ScrollPosition},
164-
* then {@link ScrollSubrangeMethodArgumentResolver} is configured as a method
165-
* argument resolver.
166-
* <li>Otherwise {@link SubrangeMethodArgumentResolver} is added.
167-
* </ul>
168-
* @since 1.2
169-
*/
170-
public void setCursorStrategy(@Nullable CursorStrategy<?> cursorStrategy) {
171-
this.cursorStrategy = cursorStrategy;
172-
}
173-
174170
/**
175171
* Add a {@link HandlerMethodArgumentResolver} for custom controller method
176172
* arguments. Such custom resolvers are ordered after built-in resolvers
@@ -270,18 +266,8 @@ private HandlerMethodArgumentResolverComposite initArgumentResolvers() {
270266
// Type based
271267
resolvers.addResolver(new DataFetchingEnvironmentMethodArgumentResolver());
272268
resolvers.addResolver(new DataLoaderMethodArgumentResolver());
273-
if (this.cursorStrategy != null) {
274-
resolvers.addResolver(createSubrangeMethodArgumentResolver(this.cursorStrategy));
275-
}
276-
if (springDataPresent) {
277-
try {
278-
resolvers.addResolver(
279-
new SortMethodArgumentResolver(obtainApplicationContext().getBean(SortStrategy.class)));
280-
}
281-
catch (NoSuchBeanDefinitionException ex) {
282-
// ignore
283-
}
284-
}
269+
addSubrangeMethodArgumentResolver(resolvers);
270+
addSortMethodArgumentResolver(resolvers);
285271
if (springSecurityPresent) {
286272
ApplicationContext context = obtainApplicationContext();
287273
resolvers.addResolver(new PrincipalMethodArgumentResolver());
@@ -299,15 +285,34 @@ private HandlerMethodArgumentResolverComposite initArgumentResolvers() {
299285
return resolvers;
300286
}
301287

302-
@SuppressWarnings("unchecked")
303-
private static HandlerMethodArgumentResolver createSubrangeMethodArgumentResolver(CursorStrategy<?> strategy) {
288+
@SuppressWarnings({"unchecked", "CastCanBeRemovedNarrowingVariableType"})
289+
private void addSubrangeMethodArgumentResolver(HandlerMethodArgumentResolverComposite resolvers) {
290+
try {
291+
CursorStrategy<?> strategy = obtainApplicationContext().getBean(CursorStrategy.class);
292+
if (springDataPresent) {
293+
if (strategy.supports(ScrollPosition.class)) {
294+
CursorStrategy<ScrollPosition> strategyToUse = (CursorStrategy<ScrollPosition>) strategy;
295+
resolvers.addResolver(new ScrollSubrangeMethodArgumentResolver(strategyToUse));
296+
return;
297+
}
298+
}
299+
resolvers.addResolver(new SubrangeMethodArgumentResolver<>(strategy));
300+
}
301+
catch (NoSuchBeanDefinitionException ex) {
302+
// ignore
303+
}
304+
}
305+
306+
private void addSortMethodArgumentResolver(HandlerMethodArgumentResolverComposite resolvers) {
304307
if (springDataPresent) {
305-
if (strategy.supports(org.springframework.data.domain.ScrollPosition.class)) {
306-
return new ScrollSubrangeMethodArgumentResolver(
307-
(CursorStrategy<org.springframework.data.domain.ScrollPosition>) strategy);
308+
try {
309+
SortStrategy strategy = obtainApplicationContext().getBean(SortStrategy.class);
310+
resolvers.addResolver(new SortMethodArgumentResolver(strategy));
311+
}
312+
catch (NoSuchBeanDefinitionException ex) {
313+
// ignore
308314
}
309315
}
310-
return new SubrangeMethodArgumentResolver<>(strategy);
311316
}
312317

313318
protected final ApplicationContext obtainApplicationContext() {

spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/SchemaMappingPaginationTests.java

+9-14
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.springframework.graphql.TestExecutionRequest;
3333
import org.springframework.graphql.data.method.annotation.QueryMapping;
3434
import org.springframework.graphql.data.pagination.ConnectionFieldTypeVisitor;
35+
import org.springframework.graphql.data.pagination.CursorStrategy;
3536
import org.springframework.graphql.data.query.ScrollPositionCursorStrategy;
3637
import org.springframework.graphql.data.query.ScrollSubrange;
3738
import org.springframework.graphql.data.query.WindowConnectionAdapter;
@@ -81,16 +82,7 @@ void forwardPagination() throws Exception {
8182
}
8283
""";
8384

84-
ExecutionGraphQlService graphQlService = graphQlService((configurer, setup) -> {
85-
86-
setup.typeDefinitionConfigurer(new ConnectionTypeDefinitionConfigurer());
87-
88-
ScrollPositionCursorStrategy cursorStrategy = new ScrollPositionCursorStrategy();
89-
WindowConnectionAdapter connectionAdapter = new WindowConnectionAdapter(cursorStrategy);
90-
setup.typeVisitor(ConnectionFieldTypeVisitor.create(List.of(connectionAdapter)));
91-
92-
configurer.setCursorStrategy(cursorStrategy);
93-
});
85+
ExecutionGraphQlService graphQlService = graphQlService();
9486

9587
ExecutionGraphQlResponse response =
9688
graphQlService.execute(TestExecutionRequest.forDocument(document)).block();
@@ -110,19 +102,22 @@ void forwardPagination() throws Exception {
110102
"}}}");
111103
}
112104

113-
private ExecutionGraphQlService graphQlService(BiConsumer<AnnotatedControllerConfigurer, GraphQlSetup> consumer) {
105+
private ExecutionGraphQlService graphQlService() {
106+
107+
ScrollPositionCursorStrategy cursorStrategy = new ScrollPositionCursorStrategy();
114108

115109
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
116110
context.register(BookController.class);
111+
context.registerBean(CursorStrategy.class, () -> cursorStrategy);
117112
context.refresh();
118113

119114
AnnotatedControllerConfigurer configurer = new AnnotatedControllerConfigurer();
120115
configurer.setApplicationContext(context);
116+
configurer.afterPropertiesSet();
121117

122118
GraphQlSetup setup = GraphQlSetup.schemaContent(SCHEMA).runtimeWiring(configurer);
123-
consumer.accept(configurer, setup);
124-
125-
configurer.afterPropertiesSet();
119+
setup.typeDefinitionConfigurer(new ConnectionTypeDefinitionConfigurer());
120+
setup.typeVisitor(ConnectionFieldTypeVisitor.create(List.of(new WindowConnectionAdapter(cursorStrategy))));
126121

127122
return setup.toGraphQlService();
128123
}

0 commit comments

Comments
 (0)