Support contructor binding for input arguments
See gh-139
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
plugins {
|
||||
id 'org.jetbrains.kotlin.jvm' version '1.5.31'
|
||||
}
|
||||
description = "GraphQL Support for Spring Applications"
|
||||
|
||||
dependencies {
|
||||
@@ -34,6 +37,7 @@ dependencies {
|
||||
|
||||
testRuntimeOnly 'org.apache.logging.log4j:log4j-core'
|
||||
testRuntimeOnly 'org.apache.logging.log4j:log4j-slf4j-impl'
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
||||
}
|
||||
|
||||
test {
|
||||
@@ -42,3 +46,16 @@ test {
|
||||
events "passed", "skipped", "failed"
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
compileKotlin {
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
}
|
||||
compileTestKotlin {
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.graphql.data.method.annotation.support;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Stack;
|
||||
@@ -107,13 +108,32 @@ public class ArgumentMethodArgumentResolver implements HandlerMethodArgumentReso
|
||||
Object target;
|
||||
if (rawValue instanceof Map) {
|
||||
Constructor<?> ctor = BeanUtils.getResolvableConstructor(targetType);
|
||||
target = BeanUtils.instantiateClass(ctor);
|
||||
DataBinder dataBinder = new DataBinder(target);
|
||||
Assert.isTrue(ctor.getParameterCount() == 0,
|
||||
() -> "Argument of type [" + targetType.getName() +
|
||||
"] cannot be instantiated because of missing default constructor.");
|
||||
MutablePropertyValues mpvs = extractPropertyValues((Map) rawValue);
|
||||
dataBinder.bind(mpvs);
|
||||
MutablePropertyValues propertyValues = extractPropertyValues((Map) rawValue);
|
||||
|
||||
if (ctor.getParameterCount() == 0) {
|
||||
target = BeanUtils.instantiateClass(ctor);
|
||||
DataBinder dataBinder = new DataBinder(target);
|
||||
dataBinder.bind(propertyValues);
|
||||
} else {
|
||||
// Data class constructor
|
||||
DataBinder binder = new DataBinder(null);
|
||||
String[] paramNames = BeanUtils.getParameterNames(ctor);
|
||||
Class<?>[] paramTypes = ctor.getParameterTypes();
|
||||
Object[] args = new Object[paramTypes.length];
|
||||
for (int i = 0; i < paramNames.length; i++) {
|
||||
String paramName = paramNames[i];
|
||||
Object value = propertyValues.get(paramName);
|
||||
value = (value instanceof List ? ((List<?>) value).toArray() : value);
|
||||
MethodParameter methodParam = new MethodParameter(ctor, i);
|
||||
if (value == null && methodParam.isOptional()) {
|
||||
args[i] = (methodParam.getParameterType() == Optional.class ? Optional.empty() : null);
|
||||
}
|
||||
else {
|
||||
args[i] = binder.convertIfNecessary(value, paramTypes[i], methodParam);
|
||||
}
|
||||
}
|
||||
target = BeanUtils.instantiateClass(ctor, args);
|
||||
}
|
||||
}
|
||||
else if (targetType.isAssignableFrom(rawValue.getClass())) {
|
||||
return returnValue(rawValue, targetType);
|
||||
|
||||
@@ -86,6 +86,18 @@ class ArgumentMethodArgumentResolverTests {
|
||||
.hasFieldOrPropertyWithValue("authorId", 42L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldResolveKotlinBeanArgument() throws Exception {
|
||||
Method addBook = ClassUtils.getMethod(BookController.class, "ktAddBook", KotlinBookInput.class);
|
||||
String payload = "{\"bookInput\": { \"name\": \"test name\", \"authorId\": 42} }";
|
||||
DataFetchingEnvironment environment = initEnvironment(payload);
|
||||
MethodParameter methodParameter = getMethodParameter(addBook, 0);
|
||||
Object result = resolver.resolveArgument(methodParameter, environment);
|
||||
assertThat(result).isNotNull().isInstanceOf(KotlinBookInput.class);
|
||||
assertThat((KotlinBookInput) result).hasFieldOrPropertyWithValue("name", "test name")
|
||||
.hasFieldOrPropertyWithValue("authorId", 42L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldResolveListOfJavaBeansArgument() throws Exception {
|
||||
Method addBooks = ClassUtils.getMethod(BookController.class, "addBooks", List.class);
|
||||
@@ -147,6 +159,11 @@ class ArgumentMethodArgumentResolverTests {
|
||||
return null;
|
||||
}
|
||||
|
||||
@MutationMapping
|
||||
public Book ktAddBook(@Argument KotlinBookInput bookInput) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@MutationMapping
|
||||
public List<Book> addBooks(@Argument List<Book> books) {
|
||||
return null;
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
package org.springframework.graphql.data.method.annotation.support;
|
||||
|
||||
data class KotlinBookInput(val name: String, val authorId: Long)
|
||||
Reference in New Issue
Block a user