From 5919178d9157527ae8911709d219237ca17a3b1c Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Thu, 9 Dec 2021 10:26:13 +0000 Subject: [PATCH] Refactoring in GraphQL argument initialization Consolidate GraphQL argument initialization by pushing logic from ArgumentMethodArgumentResolver down into GraphQlArgumentInitializer, which now takes the DataFetchingEnvironment, an optional argument name, and a target type, and does the rest of the work. --- .../data/GraphQlArgumentInitializer.java | 159 ++++++++++++------ .../AnnotatedControllerConfigurer.java | 4 +- .../ArgumentMethodArgumentResolver.java | 60 +------ .../data/query/QueryByExampleDataFetcher.java | 5 +- .../ArgumentMethodArgumentResolverTests.java | 5 +- .../GraphQlArgumentInitializerTests.java | 44 +++-- 6 files changed, 152 insertions(+), 125 deletions(-) diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/GraphQlArgumentInitializer.java b/spring-graphql/src/main/java/org/springframework/graphql/data/GraphQlArgumentInitializer.java index 8ad057c9..8775a06b 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/GraphQlArgumentInitializer.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/GraphQlArgumentInitializer.java @@ -24,14 +24,15 @@ import java.util.Map; import java.util.Optional; import java.util.Stack; +import graphql.schema.DataFetchingEnvironment; + import org.springframework.beans.BeanUtils; import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.SimpleTypeConverter; -import org.springframework.beans.TypeConverter; import org.springframework.core.CollectionFactory; import org.springframework.core.MethodParameter; +import org.springframework.core.ResolvableType; import org.springframework.core.convert.ConversionService; -import org.springframework.core.convert.TypeDescriptor; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.validation.DataBinder; @@ -56,27 +57,108 @@ public class GraphQlArgumentInitializer { /** - * Return the underlying {@link DataBinder}. + * Initialize an Object of the given {@code targetType}, either from a named + * {@link DataFetchingEnvironment#getArgument(String) argument value}, or from all + * {@link DataFetchingEnvironment#getArguments() values} as the source. + * @param environment the environment with the argument values + * @param name optionally, the name of an argument to initialize from, + * or if {@code null}, the full map of arguments is used. + * @param targetType the type of Object to initialize + * @return the initialized Object, or {@code null} */ - public TypeConverter getTypeConverter() { - return this.typeConverter; + @Nullable + @SuppressWarnings("unchecked") + public Object initializeArgument( + DataFetchingEnvironment environment, @Nullable String name, ResolvableType targetType) { + + Object sourceValue = (name != null ? environment.getArgument(name) : environment.getArguments()); + + if (sourceValue == null) { + return wrapAsOptionalIfNecessary(null, targetType); + } + + Class targetClass = targetType.resolve(); + Assert.notNull(targetClass, "Could not determine target type from " + targetType); + + // From Collection + + if (CollectionFactory.isApproximableCollectionType(sourceValue.getClass())) { + Assert.isAssignable(Collection.class, targetClass, + "Argument '" + name + "' is a Collection while method parameter is " + targetClass.getName()); + Class elementType = targetType.asCollection().getGeneric(0).resolve(); + Assert.notNull(elementType, "Could not determine element type for " + targetType); + return initializeFromCollection((Collection) sourceValue, elementType); + } + + if (targetClass == Optional.class) { + targetClass = targetType.getNested(2).resolve(); + Assert.notNull(targetClass, "Could not determine Optional type from " + targetType); + } + + // From Map + + if (sourceValue instanceof Map) { + Object target = initializeFromMap((Map) sourceValue, targetClass); + return wrapAsOptionalIfNecessary(target, targetType); + } + + // From Scalar + + if (targetClass.isInstance(sourceValue)) { + return wrapAsOptionalIfNecessary(sourceValue, targetType); + } + + Object target = this.typeConverter.convertIfNecessary(sourceValue, targetClass); + if (target == null) { + throw new IllegalStateException("Cannot convert argument value " + + "type [" + sourceValue.getClass().getName() + "] to method parameter " + + "type [" + targetClass.getName() + "]."); + } + + return wrapAsOptionalIfNecessary(target, targetType); } + @Nullable + private Object wrapAsOptionalIfNecessary(@Nullable Object value, ResolvableType type) { + return (type.resolve(Object.class).equals(Optional.class) ? Optional.ofNullable(value) : value); + } + + /** + * Instantiate a collection of {@code elementType} using the given {@code values}. + *

This will instantiate a new Collection of the closest type possible + * from the one provided as an argument. + * + * @param the type of Collection elements + * @param values the collection of values to bind and instantiate + * @param elementClass the type of elements in the given Collection + * @return the instantiated and populated Collection. + * @throws IllegalStateException if there is no suitable constructor. + */ + @SuppressWarnings("unchecked") + private Collection initializeFromCollection(Collection values, Class elementClass) { + Collection collection = CollectionFactory.createApproximateCollection(values, values.size()); + for (Object item : values) { + if (elementClass.isAssignableFrom(item.getClass())) { + collection.add((T) item); + } + else if (item instanceof Map) { + collection.add((T) this.initializeFromMap((Map) item, elementClass)); + } + else { + collection.add(this.typeConverter.convertIfNecessary(item, elementClass)); + } + } + return collection; + } /** * Instantiate an Object of the given target type and bind * {@link graphql.schema.DataFetchingEnvironment} argument values to it. - * This considers using the default constructor or a primary constructor, - * if available. - * - * @param arguments the data fetching environment arguments - * @param targetType the type of the argument to instantiate - * @param the type of the input argument - * @return the instantiated and populated input argument. + * This considers the default constructor or a primary constructor, if available. * @throws IllegalStateException if there is no suitable constructor. */ @SuppressWarnings("unchecked") - public T initializeFromMap(Map arguments, Class targetType) { + private Object initializeFromMap(Map arguments, Class targetType) { Object target; Constructor ctor = BeanUtils.getResolvableConstructor(targetType); @@ -85,7 +167,7 @@ public class GraphQlArgumentInitializer { target = BeanUtils.instantiateClass(ctor); DataBinder dataBinder = new DataBinder(target); dataBinder.bind(propertyValues); - return (T) target; + return target; } // Data class constructor @@ -96,56 +178,25 @@ public class GraphQlArgumentInitializer { for (int i = 0; i < paramNames.length; i++) { String paramName = paramNames[i]; Object value = arguments.get(paramName); - MethodParameter methodParam = new MethodParameter(ctor, i); - if (value == null && methodParam.isOptional()) { - args[i] = (methodParam.getParameterType() == Optional.class ? Optional.empty() : null); + MethodParameter methodParameter = new MethodParameter(ctor, i); + if (value == null && methodParameter.isOptional()) { + args[i] = (methodParameter.getParameterType() == Optional.class ? Optional.empty() : null); } else if (value != null && CollectionFactory.isApproximableCollectionType(value.getClass())) { - TypeDescriptor typeDescriptor = new TypeDescriptor(methodParam); - Class elementType = typeDescriptor.getElementTypeDescriptor().getType(); + ResolvableType resolvableType = ResolvableType.forMethodParameter(methodParameter); + Class elementType = resolvableType.asCollection().getGeneric(0).resolve(); + Assert.notNull(elementType, "Cannot determine element type for " + resolvableType); args[i] = initializeFromCollection((Collection) value, elementType); } else if (value instanceof Map) { - args[i] = this.initializeFromMap((Map) value, methodParam.getParameterType()); + args[i] = this.initializeFromMap((Map) value, methodParameter.getParameterType()); } else { - args[i] = this.typeConverter.convertIfNecessary(value, paramTypes[i], methodParam); + args[i] = this.typeConverter.convertIfNecessary(value, paramTypes[i], methodParameter); } } - return (T) BeanUtils.instantiateClass(ctor, args); - } - - /** - * Instantiate a collection of {@code elementType} using the given {@code values}. - *

This will instantiate a new Collection of the closest type possible - * from the one provided as an argument. - * - * @param the type of Collection elements - * @param values the collection of values to bind and instantiate - * @param elementType the type of elements in the given Collection - * @return the instantiated and populated Collection. - * @throws IllegalStateException if there is no suitable constructor. - */ - @SuppressWarnings("unchecked") - public Collection initializeFromCollection(Collection values, Class elementType) { - Assert.state(CollectionFactory.isApproximableCollectionType(values.getClass()), - () -> "Cannot instantiate Collection for type " + values.getClass()); - Collection instances = CollectionFactory.createApproximateCollection(values, values.size()); - values.forEach(item -> { - T value; - if (elementType.isAssignableFrom(item.getClass())) { - value = (T) item; - } - else if (item instanceof Map) { - value = this.initializeFromMap((Map)item, elementType); - } - else { - value = this.typeConverter.convertIfNecessary(item, elementType); - } - instances.add(value); - }); - return instances; + return BeanUtils.instantiateClass(ctor, args); } /** 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 78f9966c..610e971b 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 @@ -46,6 +46,7 @@ import org.springframework.core.MethodIntrospector; import org.springframework.core.MethodParameter; import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.convert.ConversionService; +import org.springframework.graphql.data.GraphQlArgumentInitializer; import org.springframework.graphql.data.method.HandlerMethod; import org.springframework.graphql.data.method.HandlerMethodArgumentResolver; import org.springframework.graphql.data.method.HandlerMethodArgumentResolverComposite; @@ -128,7 +129,8 @@ public class AnnotatedControllerConfigurer this.argumentResolvers.addResolver(new ProjectedPayloadMethodArgumentResolver()); } this.argumentResolvers.addResolver(new ArgumentMapMethodArgumentResolver()); - this.argumentResolvers.addResolver(new ArgumentMethodArgumentResolver(this.conversionService)); + GraphQlArgumentInitializer initializer = new GraphQlArgumentInitializer(this.conversionService); + this.argumentResolvers.addResolver(new ArgumentMethodArgumentResolver(initializer)); this.argumentResolvers.addResolver(new ContextValueMethodArgumentResolver()); // Type based 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 f17b41cc..b42af9bb 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 @@ -15,20 +15,13 @@ */ package org.springframework.graphql.data.method.annotation.support; -import java.util.Collection; -import java.util.Map; -import java.util.Optional; - import graphql.schema.DataFetchingEnvironment; -import org.springframework.core.CollectionFactory; import org.springframework.core.MethodParameter; -import org.springframework.core.convert.ConversionService; -import org.springframework.core.convert.TypeDescriptor; +import org.springframework.core.ResolvableType; import org.springframework.graphql.data.GraphQlArgumentInitializer; import org.springframework.graphql.data.method.HandlerMethodArgumentResolver; import org.springframework.graphql.data.method.annotation.Argument; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -46,8 +39,9 @@ public class ArgumentMethodArgumentResolver implements HandlerMethodArgumentReso private final GraphQlArgumentInitializer argumentInitializer; - public ArgumentMethodArgumentResolver(@Nullable ConversionService conversionService) { - this.argumentInitializer = new GraphQlArgumentInitializer(conversionService); + public ArgumentMethodArgumentResolver(GraphQlArgumentInitializer initializer) { + Assert.notNull(initializer, "GraphQlArgumentInitializer is required"); + this.argumentInitializer = initializer; } @@ -57,47 +51,10 @@ public class ArgumentMethodArgumentResolver implements HandlerMethodArgumentReso } @Override - @SuppressWarnings("unchecked") public Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment environment) throws Exception { String name = getArgumentName(parameter); - Object rawValue = environment.getArgument(name); - TypeDescriptor typeDescriptor = new TypeDescriptor(parameter); - - if (rawValue == null) { - return wrapAsOptionalIfNecessary(null, typeDescriptor.getType()); - } - - // From Collection - - if (CollectionFactory.isApproximableCollectionType(rawValue.getClass())) { - Assert.isAssignable(Collection.class, typeDescriptor.getType(), - "Argument '" + name + "' is a Collection " + - "while the @Argument method parameter is " + typeDescriptor.getType()); - Class elementType = typeDescriptor.getElementTypeDescriptor().getType(); - return this.argumentInitializer.initializeFromCollection((Collection) rawValue, elementType); - } - - Class targetType = parameter.nestedIfOptional().getNestedParameterType(); - Object target; - - // From Map - - if (rawValue instanceof Map) { - target = this.argumentInitializer.initializeFromMap((Map) rawValue, targetType); - return wrapAsOptionalIfNecessary(target, typeDescriptor.getType()); - } - - // From Scalar - - if (targetType.isAssignableFrom(rawValue.getClass())) { - return wrapAsOptionalIfNecessary(rawValue, targetType); - } - - target = this.argumentInitializer.getTypeConverter().convertIfNecessary(rawValue, targetType); - Assert.state(target != null, () -> - "Cannot convert value type [" + rawValue.getClass() + "] " + - "to argument type [" + targetType.getName() + "]."); - return wrapAsOptionalIfNecessary(target, typeDescriptor.getType()); + ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter); + return this.argumentInitializer.initializeArgument(environment, name, resolvableType); } static String getArgumentName(MethodParameter parameter) { @@ -115,9 +72,4 @@ public class ArgumentMethodArgumentResolver implements HandlerMethodArgumentReso "] not specified, and parameter name information not found in class file either."); } - @Nullable - private Object wrapAsOptionalIfNecessary(@Nullable Object value, Class type) { - return (type.equals(Optional.class) ? Optional.ofNullable(value) : value); - } - } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/query/QueryByExampleDataFetcher.java b/spring-graphql/src/main/java/org/springframework/graphql/data/query/QueryByExampleDataFetcher.java index 77b64a15..8eb257be 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/query/QueryByExampleDataFetcher.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/query/QueryByExampleDataFetcher.java @@ -30,6 +30,7 @@ import graphql.schema.GraphQLTypeVisitor; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import org.springframework.core.ResolvableType; import org.springframework.data.domain.Example; import org.springframework.data.domain.Sort; import org.springframework.data.repository.query.FluentQuery; @@ -103,8 +104,10 @@ public abstract class QueryByExampleDataFetcher { * @param env contextual info for the GraphQL query * @return the resulting example */ + @SuppressWarnings({"ConstantConditions", "unchecked"}) protected Example buildExample(DataFetchingEnvironment env) { - return Example.of(this.argumentInitializer.initializeFromMap(env.getArguments(), this.domainType.getType())); + ResolvableType targetType = ResolvableType.forClass(this.domainType.getType()); + return (Example) Example.of(this.argumentInitializer.initializeArgument(env, null, targetType)); } protected boolean requiresProjection(Class resultType) { 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 89b033f6..7a6794ab 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 @@ -33,6 +33,8 @@ import org.springframework.core.MethodParameter; import org.springframework.core.annotation.SynthesizingMethodParameter; import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.graphql.Book; +import org.springframework.graphql.data.GraphQlArgumentInitializer; +import org.springframework.graphql.data.method.HandlerMethodArgumentResolver; import org.springframework.graphql.data.method.annotation.Argument; import org.springframework.graphql.data.method.annotation.MutationMapping; import org.springframework.graphql.data.method.annotation.QueryMapping; @@ -49,7 +51,8 @@ class ArgumentMethodArgumentResolverTests { private final ObjectMapper mapper = new ObjectMapper(); - ArgumentMethodArgumentResolver resolver = new ArgumentMethodArgumentResolver(new DefaultFormattingConversionService()); + private final HandlerMethodArgumentResolver resolver = + new ArgumentMethodArgumentResolver(new GraphQlArgumentInitializer(new DefaultFormattingConversionService())); @Test void shouldSupportAnnotatedParameters() { diff --git a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/GraphQlArgumentInitializerTests.java b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/GraphQlArgumentInitializerTests.java index 4b2d59c5..960f73c1 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/GraphQlArgumentInitializerTests.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/GraphQlArgumentInitializerTests.java @@ -26,6 +26,7 @@ import graphql.schema.DataFetchingEnvironment; import graphql.schema.DataFetchingEnvironmentImpl; import org.junit.jupiter.api.Test; +import org.springframework.core.ResolvableType; import org.springframework.graphql.Book; import org.springframework.graphql.data.GraphQlArgumentInitializer; @@ -41,13 +42,15 @@ class GraphQlArgumentInitializerTests { private ObjectMapper mapper = new ObjectMapper(); - private GraphQlArgumentInitializer instantiator = new GraphQlArgumentInitializer(null); + private GraphQlArgumentInitializer initializer = new GraphQlArgumentInitializer(null); + @Test void shouldInstantiateDefaultConstructor() throws Exception { String payload = "{\"simpleBean\": { \"name\": \"test\"} }"; DataFetchingEnvironment environment = initEnvironment(payload); - SimpleBean result = instantiator.initializeFromMap(environment.getArgument("simpleBean"), SimpleBean.class); + Object result = initializer.initializeArgument( + environment, "simpleBean", ResolvableType.forClass(SimpleBean.class)); assertThat(result).isNotNull().isInstanceOf(SimpleBean.class); assertThat(result).hasFieldOrPropertyWithValue("name", "test"); @@ -57,7 +60,8 @@ class GraphQlArgumentInitializerTests { void shouldInstantiatePrimaryConstructor() throws Exception { String payload = "{\"constructorBean\": { \"name\": \"test\"} }"; DataFetchingEnvironment environment = initEnvironment(payload); - ContructorBean result = instantiator.initializeFromMap(environment.getArgument("constructorBean"), ContructorBean.class); + Object result = initializer.initializeArgument( + environment, "constructorBean", ResolvableType.forClass(ContructorBean.class)); assertThat(result).isNotNull().isInstanceOf(ContructorBean.class); assertThat(result).hasFieldOrPropertyWithValue("name", "test"); @@ -67,19 +71,21 @@ class GraphQlArgumentInitializerTests { void shouldFailIfNoPrimaryConstructor() throws Exception { String payload = "{\"noPrimary\": { \"name\": \"test\"} }"; DataFetchingEnvironment environment = initEnvironment(payload); - assertThatThrownBy(() -> instantiator.initializeFromMap(environment.getArgument("noPrimary"), NoPrimaryConstructor.class)) - .isInstanceOf(IllegalStateException.class).hasMessageContaining("No primary or single unique constructor found"); + assertThatThrownBy(() -> { + ResolvableType targetType = ResolvableType.forClass(NoPrimaryConstructor.class); + initializer.initializeArgument(environment, "noPrimary", targetType); + }).isInstanceOf(IllegalStateException.class).hasMessageContaining("No primary or single unique constructor found"); } @Test void shouldInstantiateNestedBean() throws Exception { String payload = "{\"book\": { \"name\": \"test name\", \"author\": { \"firstName\": \"Jane\", \"lastName\": \"Spring\"} } }"; DataFetchingEnvironment environment = initEnvironment(payload); - Book result = instantiator.initializeFromMap(environment.getArgument("book"), Book.class); + Object result = initializer.initializeArgument(environment, "book", ResolvableType.forClass(Book.class)); assertThat(result).isNotNull().isInstanceOf(Book.class); assertThat(result).hasFieldOrPropertyWithValue("name", "test name"); - assertThat(result.getAuthor()).isNotNull() + assertThat(((Book) result).getAuthor()).isNotNull() .hasFieldOrPropertyWithValue("firstName", "Jane") .hasFieldOrPropertyWithValue("lastName", "Spring"); } @@ -88,31 +94,35 @@ class GraphQlArgumentInitializerTests { void shouldInstantiateNestedBeanLists() throws Exception { String payload = "{\"nestedList\": { \"items\": [ {\"name\": \"first\"}, {\"name\": \"second\"}] } }"; DataFetchingEnvironment environment = initEnvironment(payload); - NestedList result = instantiator.initializeFromMap(environment.getArgument("nestedList"), NestedList.class); + Object result = initializer.initializeArgument( + environment, "nestedList", ResolvableType.forClass(NestedList.class)); assertThat(result).isNotNull().isInstanceOf(NestedList.class); - assertThat(result.getItems()).hasSize(2).extracting("name").containsExactly("first", "second"); + assertThat(((NestedList) result).getItems()).hasSize(2).extracting("name").containsExactly("first", "second"); } @Test void shouldInstantiatePrimaryConstructorNestedBeanLists() throws Exception { String payload = "{\"nestedList\": { \"items\": [ {\"name\": \"first\"}, {\"name\": \"second\"}] } }"; DataFetchingEnvironment environment = initEnvironment(payload); - PrimaryConstructorNestedList result = instantiator.initializeFromMap(environment.getArgument("nestedList"), PrimaryConstructorNestedList.class); + Object result = initializer.initializeArgument( + environment, "nestedList", ResolvableType.forClass(PrimaryConstructorNestedList.class)); assertThat(result).isNotNull().isInstanceOf(PrimaryConstructorNestedList.class); - assertThat(result.getItems()).hasSize(2).extracting("name").containsExactly("first", "second"); + assertThat(((PrimaryConstructorNestedList) result).getItems()) + .hasSize(2).extracting("name").containsExactly("first", "second"); } @Test void shouldInstantiateComplexNestedBean() throws Exception { String payload = "{\"complex\": { \"item\": {\"name\": \"Item name\"}, \"name\": \"Hello\" } }"; DataFetchingEnvironment environment = initEnvironment(payload); - PrimaryConstructorComplexInput result = instantiator.initializeFromMap(environment.getArgument("complex"), PrimaryConstructorComplexInput.class); + Object result = initializer.initializeArgument( + environment, "complex", ResolvableType.forClass(PrimaryConstructorComplexInput.class)); assertThat(result).isNotNull().isInstanceOf(PrimaryConstructorComplexInput.class); - assertThat(result.item.name).isEqualTo("Item name"); - assertThat(result.name).isEqualTo("Hello"); + assertThat(((PrimaryConstructorComplexInput) result).item.name).isEqualTo("Item name"); + assertThat(((PrimaryConstructorComplexInput) result).name).isEqualTo("Hello"); } private DataFetchingEnvironment initEnvironment(String jsonPayload) throws JsonProcessingException { @@ -121,6 +131,7 @@ class GraphQlArgumentInitializerTests { return DataFetchingEnvironmentImpl.newDataFetchingEnvironment().arguments(arguments).build(); } + static class SimpleBean { String name; @@ -134,6 +145,7 @@ class GraphQlArgumentInitializerTests { } } + static class ContructorBean { final String name; @@ -147,6 +159,7 @@ class GraphQlArgumentInitializerTests { } } + static class NoPrimaryConstructor { NoPrimaryConstructor(String name) { @@ -156,6 +169,7 @@ class GraphQlArgumentInitializerTests { } } + static class NestedList { List items; @@ -182,6 +196,7 @@ class GraphQlArgumentInitializerTests { } } + static class Item { String name; @@ -195,6 +210,7 @@ class GraphQlArgumentInitializerTests { } } + static class PrimaryConstructorComplexInput { final String name;