diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ArgumentMethodArgumentResolver.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ArgumentMethodArgumentResolver.java index 617e19b2f..cfa2374de 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ArgumentMethodArgumentResolver.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ArgumentMethodArgumentResolver.java @@ -74,10 +74,19 @@ public Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment if (CollectionFactory.isApproximableCollectionType(rawValue.getClass())) { Assert.isAssignable(Collection.class, parameterType.getType(), "Argument '" + name + "' is a Collection while the @Argument method parameter is " + parameterType.getType()); + + if (parameterType.getElementTypeDescriptor().getType() == Map.class) { + return rawValue; + } + Class elementType = parameterType.getElementTypeDescriptor().getType(); return this.instantiator.instantiateCollection(elementType, (Collection) rawValue); } + if (parameterType.isMap()) { + return rawValue; + } + MethodParameter nestedParameter = parameter.nestedIfOptional(); Object value = convert(rawValue, nestedParameter.getNestedParameterType()); return returnValue(value, parameterType.getType()); diff --git a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/ArgumentMethodArgumentResolverTests.java b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/ArgumentMethodArgumentResolverTests.java index ee327e266..37a82916e 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/ArgumentMethodArgumentResolverTests.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/ArgumentMethodArgumentResolverTests.java @@ -18,6 +18,7 @@ import java.lang.reflect.Method; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -98,6 +99,32 @@ void shouldResolveListOfJavaBeansArgument() throws Exception { .extracting("name").containsExactly("first", "second"); } + @Test + void shouldPassArgumentAsMap() throws Exception { + Method updateBook = ClassUtils.getMethod(BookController.class, "updateBook", Long.class, Map.class); + String payload = "{\"id\": 43, \"input\": { \"name\": \"new name\", \"description\": null, \"authorId\": 42} }"; + DataFetchingEnvironment environment = initEnvironment(payload); + MethodParameter methodParameter = getMethodParameter(updateBook, 1); + Object result = resolver.resolveArgument(methodParameter, environment); + assertThat(result).isNotNull().isInstanceOf(Map.class); + assertThat(result) + .hasFieldOrPropertyWithValue("name", "new name") + .hasFieldOrPropertyWithValue("description", null) + .hasFieldOrPropertyWithValue("authorId", 42); + } + + @Test + void shouldPassArgumentAsList() throws Exception { + Method updateBook = ClassUtils.getMethod(BookController.class, "updateBooks", List.class); + String payload = "{\"input\": [{ \"id\": 1, \"name\": \"first\" }, { \"id\": 2, \"name\": \"second\" }] }"; + DataFetchingEnvironment environment = initEnvironment(payload); + MethodParameter methodParameter = getMethodParameter(updateBook, 0); + Object result = resolver.resolveArgument(methodParameter, environment); + assertThat(result).isNotNull().isInstanceOf(List.class); + assertThat(result).asList().allMatch(item -> item instanceof Map) + .extracting("name").containsExactly("first", "second"); + } + private MethodParameter getMethodParameter(Method method, int index) { MethodParameter methodParameter = new MethodParameter(method, index); methodParameter.initParameterNameDiscovery(new DefaultParameterNameDiscoverer()); @@ -132,6 +159,16 @@ public List addBooks(@Argument List books) { return null; } + @MutationMapping + public List updateBook(@Argument Long id, @Argument Map input) { + return null; + } + + @MutationMapping + public List updateBooks(@Argument List> input) { + return null; + } + } static class BookInput {