diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerConfigurer.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerConfigurer.java
index 14d6575f..1f94d16c 100644
--- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerConfigurer.java
+++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerConfigurer.java
@@ -58,6 +58,7 @@ import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.convert.ConversionService;
+import org.springframework.data.domain.ScrollPosition;
import org.springframework.format.FormatterRegistrar;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.format.support.FormattingConversionService;
@@ -82,14 +83,27 @@ import org.springframework.util.StringUtils;
import org.springframework.validation.DataBinder;
/**
- * {@link RuntimeWiringConfigurer} that detects {@link SchemaMapping @SchemaMapping}
- * annotated handler methods in {@link Controller @Controller} classes and
- * registers them as {@link DataFetcher}s.
+ * {@link RuntimeWiringConfigurer} that finds {@link SchemaMapping @SchemaMapping}
+ * annotated handler methods in {@link Controller @Controller} classes declared in
+ * Spring configuration, and registers them as {@link DataFetcher}s.
*
*
In addition to initializing a {@link RuntimeWiring.Builder}, this class, also
* provides an option to {@link #configure(GraphQLCodeRegistry.Builder) configure}
* data fetchers on a {@link GraphQLCodeRegistry.Builder}.
*
+ *
This class detects the following strategies in Spring configuration,
+ * expecting to find a single, unique bean of that type:
+ *
+ * - {@link CursorStrategy} -- if Spring Data is present, and the strategy
+ * supports {@code ScrollPosition}, then {@link ScrollSubrangeMethodArgumentResolver}
+ * is configured for use. If not, then {@link SubrangeMethodArgumentResolver}
+ * is added instead.
+ *
- {@link SortStrategy} -- if present, then {@link SortMethodArgumentResolver}
+ * is configured for use.
+ *
+ *
+ *
+ *
* @author Rossen Stoyanchev
* @author Brian Clozel
* @since 1.0.0
@@ -125,9 +139,6 @@ public class AnnotatedControllerConfigurer implements ApplicationContextAware, I
private final FormattingConversionService conversionService = new DefaultFormattingConversionService();
- @Nullable
- private CursorStrategy> cursorStrategy;
-
private final List customArgumentResolvers = new ArrayList<>(8);
@Nullable
@@ -156,21 +167,6 @@ public class AnnotatedControllerConfigurer implements ApplicationContextAware, I
registrar.registerFormatters(this.conversionService);
}
- /**
- * Configure a {@link CursorStrategy} to handle pagination requests, which
- * results in one of the following:
- *
- * - If Spring Data is present, and the strategy supports {@code ScrollPosition},
- * then {@link ScrollSubrangeMethodArgumentResolver} is configured as a method
- * argument resolver.
- *
- Otherwise {@link SubrangeMethodArgumentResolver} is added.
- *
- * @since 1.2
- */
- public void setCursorStrategy(@Nullable CursorStrategy> cursorStrategy) {
- this.cursorStrategy = cursorStrategy;
- }
-
/**
* Add a {@link HandlerMethodArgumentResolver} for custom controller method
* arguments. Such custom resolvers are ordered after built-in resolvers
@@ -270,18 +266,8 @@ public class AnnotatedControllerConfigurer implements ApplicationContextAware, I
// Type based
resolvers.addResolver(new DataFetchingEnvironmentMethodArgumentResolver());
resolvers.addResolver(new DataLoaderMethodArgumentResolver());
- if (this.cursorStrategy != null) {
- resolvers.addResolver(createSubrangeMethodArgumentResolver(this.cursorStrategy));
- }
- if (springDataPresent) {
- try {
- resolvers.addResolver(
- new SortMethodArgumentResolver(obtainApplicationContext().getBean(SortStrategy.class)));
- }
- catch (NoSuchBeanDefinitionException ex) {
- // ignore
- }
- }
+ addSubrangeMethodArgumentResolver(resolvers);
+ addSortMethodArgumentResolver(resolvers);
if (springSecurityPresent) {
ApplicationContext context = obtainApplicationContext();
resolvers.addResolver(new PrincipalMethodArgumentResolver());
@@ -299,15 +285,34 @@ public class AnnotatedControllerConfigurer implements ApplicationContextAware, I
return resolvers;
}
- @SuppressWarnings("unchecked")
- private static HandlerMethodArgumentResolver createSubrangeMethodArgumentResolver(CursorStrategy> strategy) {
+ @SuppressWarnings({"unchecked", "CastCanBeRemovedNarrowingVariableType"})
+ private void addSubrangeMethodArgumentResolver(HandlerMethodArgumentResolverComposite resolvers) {
+ try {
+ CursorStrategy> strategy = obtainApplicationContext().getBean(CursorStrategy.class);
+ if (springDataPresent) {
+ if (strategy.supports(ScrollPosition.class)) {
+ CursorStrategy strategyToUse = (CursorStrategy) strategy;
+ resolvers.addResolver(new ScrollSubrangeMethodArgumentResolver(strategyToUse));
+ return;
+ }
+ }
+ resolvers.addResolver(new SubrangeMethodArgumentResolver<>(strategy));
+ }
+ catch (NoSuchBeanDefinitionException ex) {
+ // ignore
+ }
+ }
+
+ private void addSortMethodArgumentResolver(HandlerMethodArgumentResolverComposite resolvers) {
if (springDataPresent) {
- if (strategy.supports(org.springframework.data.domain.ScrollPosition.class)) {
- return new ScrollSubrangeMethodArgumentResolver(
- (CursorStrategy) strategy);
+ try {
+ SortStrategy strategy = obtainApplicationContext().getBean(SortStrategy.class);
+ resolvers.addResolver(new SortMethodArgumentResolver(strategy));
+ }
+ catch (NoSuchBeanDefinitionException ex) {
+ // ignore
}
}
- return new SubrangeMethodArgumentResolver<>(strategy);
}
protected final ApplicationContext obtainApplicationContext() {
diff --git a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/SchemaMappingPaginationTests.java b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/SchemaMappingPaginationTests.java
index 877912f0..f95d31fe 100644
--- a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/SchemaMappingPaginationTests.java
+++ b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/SchemaMappingPaginationTests.java
@@ -32,6 +32,7 @@ import org.springframework.graphql.GraphQlSetup;
import org.springframework.graphql.TestExecutionRequest;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.graphql.data.pagination.ConnectionFieldTypeVisitor;
+import org.springframework.graphql.data.pagination.CursorStrategy;
import org.springframework.graphql.data.query.ScrollPositionCursorStrategy;
import org.springframework.graphql.data.query.ScrollSubrange;
import org.springframework.graphql.data.query.WindowConnectionAdapter;
@@ -81,16 +82,7 @@ public class SchemaMappingPaginationTests {
}
""";
- ExecutionGraphQlService graphQlService = graphQlService((configurer, setup) -> {
-
- setup.typeDefinitionConfigurer(new ConnectionTypeDefinitionConfigurer());
-
- ScrollPositionCursorStrategy cursorStrategy = new ScrollPositionCursorStrategy();
- WindowConnectionAdapter connectionAdapter = new WindowConnectionAdapter(cursorStrategy);
- setup.typeVisitor(ConnectionFieldTypeVisitor.create(List.of(connectionAdapter)));
-
- configurer.setCursorStrategy(cursorStrategy);
- });
+ ExecutionGraphQlService graphQlService = graphQlService();
ExecutionGraphQlResponse response =
graphQlService.execute(TestExecutionRequest.forDocument(document)).block();
@@ -110,19 +102,22 @@ public class SchemaMappingPaginationTests {
"}}}");
}
- private ExecutionGraphQlService graphQlService(BiConsumer consumer) {
+ private ExecutionGraphQlService graphQlService() {
+
+ ScrollPositionCursorStrategy cursorStrategy = new ScrollPositionCursorStrategy();
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(BookController.class);
+ context.registerBean(CursorStrategy.class, () -> cursorStrategy);
context.refresh();
AnnotatedControllerConfigurer configurer = new AnnotatedControllerConfigurer();
configurer.setApplicationContext(context);
+ configurer.afterPropertiesSet();
GraphQlSetup setup = GraphQlSetup.schemaContent(SCHEMA).runtimeWiring(configurer);
- consumer.accept(configurer, setup);
-
- configurer.afterPropertiesSet();
+ setup.typeDefinitionConfigurer(new ConnectionTypeDefinitionConfigurer());
+ setup.typeVisitor(ConnectionFieldTypeVisitor.create(List.of(new WindowConnectionAdapter(cursorStrategy))));
return setup.toGraphQlService();
}