Skip to content

Commit 6975e6c

Browse files
committed
Configure ConversionService for argument conversion
This commit configures a `FormattingConversionService` into the argument resolution infrastructure, using the expected conversion service for both MVC and WebFlux. Closes gh-148
1 parent a66b495 commit 6975e6c

File tree

8 files changed

+75
-11
lines changed

8 files changed

+75
-11
lines changed

graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/GraphQlAutoConfiguration.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
import org.springframework.context.annotation.Configuration;
3737
import org.springframework.core.io.Resource;
3838
import org.springframework.core.io.support.ResourcePatternResolver;
39-
import org.springframework.graphql.data.method.annotation.support.AnnotatedControllerConfigurer;
4039
import org.springframework.graphql.execution.DataFetcherExceptionResolver;
4140
import org.springframework.graphql.execution.GraphQlSource;
4241
import org.springframework.graphql.execution.MissingSchemaException;
@@ -57,11 +56,6 @@ public class GraphQlAutoConfiguration {
5756

5857
private static final Log logger = LogFactory.getLog(GraphQlAutoConfiguration.class);
5958

60-
@Bean
61-
public AnnotatedControllerConfigurer annotatedControllerConfigurer() {
62-
return new AnnotatedControllerConfigurer();
63-
}
64-
6559
@Bean
6660
public GraphQlSource graphQlSource(ResourcePatternResolver resourcePatternResolver, GraphQlProperties properties,
6761
ObjectProvider<DataFetcherExceptionResolver> exceptionResolversProvider,

graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/GraphQlWebFluxAutoConfiguration.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.apache.commons.logging.LogFactory;
2525

2626
import org.springframework.beans.factory.ObjectProvider;
27+
import org.springframework.beans.factory.annotation.Qualifier;
2728
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
2829
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
2930
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
@@ -36,7 +37,9 @@
3637
import org.springframework.context.annotation.Configuration;
3738
import org.springframework.core.io.Resource;
3839
import org.springframework.core.io.ResourceLoader;
40+
import org.springframework.format.support.FormattingConversionService;
3941
import org.springframework.graphql.GraphQlService;
42+
import org.springframework.graphql.data.method.annotation.support.AnnotatedControllerConfigurer;
4043
import org.springframework.graphql.execution.GraphQlSource;
4144
import org.springframework.graphql.web.WebGraphQlHandler;
4245
import org.springframework.graphql.web.WebInterceptor;
@@ -78,6 +81,13 @@ public class GraphQlWebFluxAutoConfiguration {
7881

7982
private static final Log logger = LogFactory.getLog(GraphQlWebFluxAutoConfiguration.class);
8083

84+
@Bean
85+
public AnnotatedControllerConfigurer annotatedControllerConfigurer(@Qualifier("webFluxConversionService") FormattingConversionService conversionService) {
86+
AnnotatedControllerConfigurer annotatedControllerConfigurer = new AnnotatedControllerConfigurer();
87+
annotatedControllerConfigurer.setConversionService(conversionService);
88+
return annotatedControllerConfigurer;
89+
}
90+
8191
@Bean
8292
@ConditionalOnBean(GraphQlService.class)
8393
@ConditionalOnMissingBean

graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/GraphQlWebMvcAutoConfiguration.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.apache.commons.logging.LogFactory;
2828

2929
import org.springframework.beans.factory.ObjectProvider;
30+
import org.springframework.beans.factory.annotation.Qualifier;
3031
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
3132
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
3233
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
@@ -40,7 +41,9 @@
4041
import org.springframework.context.annotation.Configuration;
4142
import org.springframework.core.io.Resource;
4243
import org.springframework.core.io.ResourceLoader;
44+
import org.springframework.format.support.FormattingConversionService;
4345
import org.springframework.graphql.GraphQlService;
46+
import org.springframework.graphql.data.method.annotation.support.AnnotatedControllerConfigurer;
4447
import org.springframework.graphql.execution.GraphQlSource;
4548
import org.springframework.graphql.execution.ThreadLocalAccessor;
4649
import org.springframework.graphql.web.WebGraphQlHandler;
@@ -85,6 +88,12 @@ public class GraphQlWebMvcAutoConfiguration {
8588

8689
private static final Log logger = LogFactory.getLog(GraphQlWebMvcAutoConfiguration.class);
8790

91+
@Bean
92+
public AnnotatedControllerConfigurer annotatedControllerConfigurer(@Qualifier("mvcConversionService") FormattingConversionService conversionService) {
93+
AnnotatedControllerConfigurer annotatedControllerConfigurer = new AnnotatedControllerConfigurer();
94+
annotatedControllerConfigurer.setConversionService(conversionService);
95+
return annotatedControllerConfigurer;
96+
}
8897

8998
@Bean
9099
@ConditionalOnBean(GraphQlService.class)

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import org.springframework.core.MethodIntrospector;
4646
import org.springframework.core.MethodParameter;
4747
import org.springframework.core.annotation.AnnotatedElementUtils;
48+
import org.springframework.core.convert.ConversionService;
4849
import org.springframework.graphql.data.method.HandlerMethod;
4950
import org.springframework.graphql.data.method.HandlerMethodArgumentResolver;
5051
import org.springframework.graphql.data.method.HandlerMethodArgumentResolverComposite;
@@ -90,12 +91,19 @@ public class AnnotatedControllerConfigurer
9091
@Nullable
9192
private HandlerMethodArgumentResolverComposite argumentResolvers;
9293

94+
@Nullable
95+
private ConversionService conversionService;
96+
9397

9498
@Override
9599
public void setApplicationContext(ApplicationContext applicationContext) {
96100
this.applicationContext = applicationContext;
97101
}
98102

103+
public void setConversionService(ConversionService conversionService) {
104+
this.conversionService = conversionService;
105+
}
106+
99107
protected final ApplicationContext obtainApplicationContext() {
100108
Assert.state(this.applicationContext != null, "No ApplicationContext");
101109
return this.applicationContext;
@@ -106,7 +114,7 @@ protected final ApplicationContext obtainApplicationContext() {
106114
public void afterPropertiesSet() {
107115
this.argumentResolvers = new HandlerMethodArgumentResolverComposite();
108116
this.argumentResolvers.addResolver(new ArgumentMapMethodArgumentResolver());
109-
this.argumentResolvers.addResolver(new ArgumentMethodArgumentResolver());
117+
this.argumentResolvers.addResolver(new ArgumentMethodArgumentResolver(this.conversionService));
110118
this.argumentResolvers.addResolver(new DataFetchingEnvironmentMethodArgumentResolver());
111119
this.argumentResolvers.addResolver(new DataLoaderMethodArgumentResolver());
112120

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@
2323

2424
import org.springframework.core.CollectionFactory;
2525
import org.springframework.core.MethodParameter;
26+
import org.springframework.core.convert.ConversionService;
2627
import org.springframework.core.convert.TypeDescriptor;
2728
import org.springframework.graphql.data.method.HandlerMethodArgumentResolver;
2829
import org.springframework.graphql.data.method.annotation.Argument;
30+
import org.springframework.lang.Nullable;
2931
import org.springframework.util.Assert;
3032
import org.springframework.util.StringUtils;
3133
import org.springframework.validation.DataBinder;
@@ -41,7 +43,14 @@
4143
*/
4244
public class ArgumentMethodArgumentResolver implements HandlerMethodArgumentResolver {
4345

44-
private final GraphQlArgumentInstantiator instantiator = new GraphQlArgumentInstantiator();
46+
private final GraphQlArgumentInstantiator instantiator;
47+
48+
private final ConversionService conversionService;
49+
50+
public ArgumentMethodArgumentResolver(@Nullable ConversionService conversionService) {
51+
this.conversionService = conversionService;
52+
this.instantiator = new GraphQlArgumentInstantiator(conversionService);
53+
}
4554

4655
@Override
4756
public boolean supportsParameter(MethodParameter parameter) {
@@ -100,6 +109,7 @@ else if (targetType.isAssignableFrom(rawValue.getClass())) {
100109
}
101110
else {
102111
DataBinder converter = new DataBinder(null);
112+
converter.setConversionService(this.conversionService);
103113
target = converter.convertIfNecessary(rawValue, targetType);
104114
Assert.isTrue(target != null,
105115
() -> "Value of type [" + rawValue.getClass() + "] cannot be converted to argument of type [" +

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
import org.springframework.beans.MutablePropertyValues;
2929
import org.springframework.core.CollectionFactory;
3030
import org.springframework.core.MethodParameter;
31+
import org.springframework.core.convert.ConversionService;
3132
import org.springframework.core.convert.TypeDescriptor;
33+
import org.springframework.lang.Nullable;
3234
import org.springframework.util.Assert;
3335
import org.springframework.validation.DataBinder;
3436

@@ -40,7 +42,12 @@
4042
*/
4143
class GraphQlArgumentInstantiator {
4244

43-
private final DataBinder converter = new DataBinder(null);
45+
private final DataBinder converter;
46+
47+
public GraphQlArgumentInstantiator(@Nullable ConversionService conversionService) {
48+
this.converter = new DataBinder(null);
49+
this.converter.setConversionService(conversionService);
50+
}
4451

4552
/**
4653
* Instantiate the given target type and bind data from

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

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030

3131
import org.springframework.core.DefaultParameterNameDiscoverer;
3232
import org.springframework.core.MethodParameter;
33+
import org.springframework.format.support.DefaultFormattingConversionService;
34+
import org.springframework.format.support.FormattingConversionService;
3335
import org.springframework.graphql.Book;
3436
import org.springframework.graphql.data.method.annotation.Argument;
3537
import org.springframework.graphql.data.method.annotation.MutationMapping;
@@ -48,7 +50,7 @@ class ArgumentMethodArgumentResolverTests {
4850

4951
private final ObjectMapper mapper = new ObjectMapper();
5052

51-
ArgumentMethodArgumentResolver resolver = new ArgumentMethodArgumentResolver();
53+
ArgumentMethodArgumentResolver resolver = new ArgumentMethodArgumentResolver(new DefaultFormattingConversionService());
5254

5355
@Test
5456
void shouldSupportAnnotatedParameters() {
@@ -98,6 +100,17 @@ void shouldResolveListOfJavaBeansArgument() throws Exception {
98100
.extracting("name").containsExactly("first", "second");
99101
}
100102

103+
@Test
104+
void shouldResolveArgumentWithConversionService() throws Exception {
105+
Method bookByKeyword = ClassUtils.getMethod(BookController.class, "bookByKeyword", Keyword.class);
106+
String payload = "{\"keyword\": \"test\" }";
107+
DataFetchingEnvironment environment = initEnvironment(payload);
108+
MethodParameter methodParameter = getMethodParameter(bookByKeyword, 0);
109+
Object result = resolver.resolveArgument(methodParameter, environment);
110+
assertThat(result).isNotNull().isInstanceOf(Keyword.class);
111+
assertThat((Keyword) result).hasFieldOrPropertyWithValue("term", "test");
112+
}
113+
101114
private MethodParameter getMethodParameter(Method method, int index) {
102115
MethodParameter methodParameter = new MethodParameter(method, index);
103116
methodParameter.initParameterNameDiscovery(new DefaultParameterNameDiscoverer());
@@ -132,6 +145,11 @@ public List<Book> addBooks(@Argument List<Book> books) {
132145
return null;
133146
}
134147

148+
@QueryMapping
149+
public List<Book> bookByKeyword(@Argument Keyword keyword) {
150+
return null;
151+
}
152+
135153
}
136154

137155
static class BookInput {
@@ -161,6 +179,14 @@ static class Keyword {
161179

162180
String term;
163181

182+
private Keyword(String term) {
183+
this.term = term;
184+
}
185+
186+
public static Keyword of(String term) {
187+
return new Keyword(term);
188+
}
189+
164190
public String getTerm() {
165191
return this.term;
166192
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class GraphQlArgumentInstantiatorTests {
4040

4141
private ObjectMapper mapper = new ObjectMapper();
4242

43-
private GraphQlArgumentInstantiator instantiator = new GraphQlArgumentInstantiator();
43+
private GraphQlArgumentInstantiator instantiator = new GraphQlArgumentInstantiator(null);
4444

4545
@Test
4646
void shouldInstantiateDefaultConstructor() throws Exception {

0 commit comments

Comments
 (0)