Merge branch '1.0.x'

This commit is contained in:
rstoyanchev
2022-07-05 08:51:20 +01:00
2 changed files with 47 additions and 16 deletions

View File

@@ -128,7 +128,7 @@ public class GraphQlArgumentBinder {
try {
// From Collection
if (CollectionFactory.isApproximableCollectionType(rawValue.getClass())) {
if (isApproximableCollectionType(rawValue)) {
segments.push(argumentName);
return createCollection((Collection<Object>) rawValue, targetType, bindingResult, segments);
}
@@ -164,6 +164,11 @@ public class GraphQlArgumentBinder {
return (type.resolve(Object.class).equals(Optional.class) ? Optional.ofNullable(value) : value);
}
private boolean isApproximableCollectionType(Object rawValue) {
return (CollectionFactory.isApproximableCollectionType(rawValue.getClass()) ||
rawValue instanceof List); // it may be SingletonList
}
@SuppressWarnings({"ConstantConditions", "unchecked"})
private <T> Collection<T> createCollection(
Collection<Object> rawCollection, ResolvableType collectionType,
@@ -253,7 +258,7 @@ public class GraphQlArgumentBinder {
if (rawValue == null && methodParam.isOptional()) {
args[i] = (paramTypes[i] == Optional.class ? Optional.empty() : null);
}
else if (rawValue != null && CollectionFactory.isApproximableCollectionType(rawValue.getClass())) {
else if (rawValue != null && isApproximableCollectionType(rawValue)) {
ResolvableType elementType = ResolvableType.forMethodParameter(methodParam);
args[i] = createCollection((Collection<Object>) rawValue, elementType, bindingResult, segments);
}

View File

@@ -14,8 +14,10 @@
* limitations under the License.
*/
package org.springframework.graphql.data.method.annotation.support;
package org.springframework.graphql.data;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -45,14 +47,13 @@ class GraphQlArgumentBinderTests {
private final ObjectMapper mapper = new ObjectMapper();
private final ThreadLocal<GraphQlArgumentBinder> initializer =
ThreadLocal.withInitial(() -> new GraphQlArgumentBinder(null));
private final GraphQlArgumentBinder binder = new GraphQlArgumentBinder(null);
@Test
void defaultConstructor() throws Exception {
Object result = initializer.get().bind(
Object result = this.binder.bind(
environment("{\"key\":{\"name\":\"test\"}}"), "key",
ResolvableType.forClass(SimpleBean.class));
@@ -63,7 +64,7 @@ class GraphQlArgumentBinderTests {
@Test
void defaultConstructorWithNestedBeanProperty() throws Exception {
Object result = initializer.get().bind(
Object result = this.binder.bind(
environment(
"{\"key\":{" +
"\"name\":\"test name\"," +
@@ -84,7 +85,7 @@ class GraphQlArgumentBinderTests {
@Test
void defaultConstructorWithNestedBeanListProperty() throws Exception {
Object result = initializer.get().bind(
Object result = this.binder.bind(
environment("{\"key\":{\"items\":[{\"name\":\"first\"},{\"name\":\"second\"}]}}"), "key",
ResolvableType.forClass(ItemListHolder.class));
@@ -96,7 +97,7 @@ class GraphQlArgumentBinderTests {
@Test // gh-301
void defaultConstructorWithNestedBeanListEmpty() throws Exception {
Object result = initializer.get().bind(
Object result = this.binder.bind(
environment("{\"key\":{\"items\": []}}"), "key",
ResolvableType.forClass(ItemListHolder.class));
@@ -108,7 +109,7 @@ class GraphQlArgumentBinderTests {
void defaultConstructorBindingError() {
assertThatThrownBy(
() -> initializer.get().bind(
() -> this.binder.bind(
environment("{\"key\":{\"name\":\"test\",\"age\":\"invalid\"}}"), "key",
ResolvableType.forClass(SimpleBean.class)))
.extracting(ex -> ((BindException) ex).getFieldErrors())
@@ -123,7 +124,7 @@ class GraphQlArgumentBinderTests {
@Test
void primaryConstructor() throws Exception {
Object result = initializer.get().bind(
Object result = this.binder.bind(
environment("{\"key\":{\"name\":\"test\"}}"), "key",
ResolvableType.forClass(PrimaryConstructorBean.class));
@@ -134,7 +135,7 @@ class GraphQlArgumentBinderTests {
@Test
void primaryConstructorWithBeanArgument() throws Exception {
Object result = initializer.get().bind(
Object result = this.binder.bind(
environment(
"{\"key\":{" +
"\"item\":{\"name\":\"Item name\"}," +
@@ -152,7 +153,7 @@ class GraphQlArgumentBinderTests {
@Test
void primaryConstructorWithNestedBeanList() throws Exception {
Object result = initializer.get().bind(
Object result = this.binder.bind(
environment(
"{\"key\":{\"items\":[" +
"{\"name\":\"first\"}," +
@@ -168,7 +169,7 @@ class GraphQlArgumentBinderTests {
@Test
void primaryConstructorNotFound() {
assertThatThrownBy(
() -> initializer.get().bind(
() -> this.binder.bind(
environment("{\"key\":{\"name\":\"test\"}}"), "key",
ResolvableType.forClass(NoPrimaryConstructorBean.class)))
.isInstanceOf(IllegalStateException.class)
@@ -179,7 +180,7 @@ class GraphQlArgumentBinderTests {
void primaryConstructorBindingError() {
assertThatThrownBy(
() -> initializer.get().bind(
() -> this.binder.bind(
environment(
"{\"key\":{" +
"\"name\":\"Hello\"," +
@@ -205,7 +206,7 @@ class GraphQlArgumentBinderTests {
void primaryConstructorBindingErrorWithNestedBeanList() {
assertThatThrownBy(
() -> initializer.get().bind(
() -> this.binder.bind(
environment(
"{\"key\":{\"items\":[" +
"{\"name\":\"first\", \"age\":\"invalid\"}," +
@@ -225,6 +226,31 @@ class GraphQlArgumentBinderTests {
});
}
@Test // gh-410
void coercionWithSingletonList() throws Exception {
Map<String, String> itemMap = new HashMap<>();
itemMap.put("name", "Joe");
itemMap.put("age", "37");
Map<String, Object> arguments = new HashMap<>();
arguments.put("key", Collections.singletonList(itemMap));
DataFetchingEnvironment environment =
DataFetchingEnvironmentImpl.newDataFetchingEnvironment().arguments(arguments).build();
Object result = this.binder.bind(environment, "key",
ResolvableType.forClassWithGenerics(List.class, Item.class));
assertThat(result).isNotNull().isInstanceOf(List.class);
List<Item> items = (List<Item>) result;
assertThat(items).hasSize(1);
assertThat(items.get(0).getName()).isEqualTo("Joe");
assertThat(items.get(0).getAge()).isEqualTo(37);
}
@SuppressWarnings("unchecked")
private DataFetchingEnvironment environment(String jsonPayload) throws JsonProcessingException {
Map<String, Object> arguments = this.mapper.readValue(jsonPayload, Map.class);