Skip to content

Commit aa8bb81

Browse files
committed
Avoid further setter binding when possible
As of gh-1163, the `GraphQlArgumentBinder` can bind using both a constructor and setters. This is especially useful for Kotlin data classes. This change introduced a significant performance penalty for large and deep data sets. This commit ensures that we are only performing setter binding for input data that was not already consumed during the constructor binding phase. Fixes gh-1284
1 parent dfa486b commit aa8bb81

File tree

1 file changed

+7
-4
lines changed

1 file changed

+7
-4
lines changed

spring-graphql/src/main/java/org/springframework/graphql/data/GraphQlArgumentBinder.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.lang.reflect.Field;
2121
import java.util.Collection;
2222
import java.util.Collections;
23+
import java.util.HashMap;
2324
import java.util.Map;
2425
import java.util.Optional;
2526

@@ -276,6 +277,7 @@ private Map<?, Object> bindMapToMap(
276277
private Object bindViaConstructorAndSetters(Constructor<?> constructor,
277278
Map<String, Object> rawMap, ResolvableType ownerType, ArgumentsBindingResult bindingResult) {
278279

280+
Map<String, Object> dataToBind = new HashMap<>(rawMap);
279281
String[] paramNames = BeanUtils.getParameterNames(constructor);
280282
Class<?>[] paramTypes = constructor.getParameterTypes();
281283
Object[] constructorArguments = new Object[paramTypes.length];
@@ -287,7 +289,8 @@ private Object bindViaConstructorAndSetters(Constructor<?> constructor,
287289
ResolvableType.forConstructorParameter(constructor, i).getType(), ownerType);
288290

289291
constructorArguments[i] = bindRawValue(
290-
name, rawMap.get(name), !rawMap.containsKey(name), targetType, paramTypes[i], bindingResult);
292+
name, dataToBind.get(name), !dataToBind.containsKey(name), targetType, paramTypes[i], bindingResult);
293+
dataToBind.remove(name);
291294
}
292295

293296
Object target;
@@ -302,9 +305,9 @@ private Object bindViaConstructorAndSetters(Constructor<?> constructor,
302305
throw ex;
303306
}
304307

305-
// If no errors, apply setters too
306-
if (!bindingResult.hasErrors()) {
307-
bindViaSetters(target, rawMap, ownerType, bindingResult);
308+
// If no errors and data remains to be bound, apply setters too
309+
if (!dataToBind.isEmpty() && !bindingResult.hasErrors()) {
310+
bindViaSetters(target, dataToBind, ownerType, bindingResult);
308311
}
309312

310313
return target;

0 commit comments

Comments
 (0)