@@ -71,7 +71,7 @@ public class GraphQlArgumentBinder {
71
71
72
72
private final BindingErrorProcessor bindingErrorProcessor = new DefaultBindingErrorProcessor ();
73
73
74
- private List <Consumer <DataBinder >> dataBinderInitializers = new ArrayList <>();
74
+ private final List <Consumer <DataBinder >> dataBinderInitializers = new ArrayList <>();
75
75
76
76
77
77
public GraphQlArgumentBinder () {
@@ -160,7 +160,7 @@ public Object bind(
160
160
// From Map
161
161
162
162
if (rawValue instanceof Map ) {
163
- Object target = createValue ((Map <String , Object >) rawValue , targetClass , bindingResult , segments );
163
+ Object target = createValue ((Map <String , Object >) rawValue , targetType , bindingResult , segments );
164
164
return wrapAsOptionalIfNecessary (target , targetType );
165
165
}
166
166
@@ -204,6 +204,7 @@ private <T> Collection<T> createCollection(
204
204
return Collections .emptyList ();
205
205
}
206
206
207
+ ResolvableType elementType = collectionType .asCollection ().getGeneric (0 );
207
208
Class <?> elementClass = collectionType .asCollection ().getGeneric (0 ).resolve ();
208
209
if (elementClass == null ) {
209
210
bindingResult .rejectValue (toArgumentPath (segments ), "unknownElementType" , "Unknown element type" );
@@ -218,7 +219,7 @@ private <T> Collection<T> createCollection(
218
219
collection .add ((T ) rawValue );
219
220
}
220
221
else if (rawValue instanceof Map ) {
221
- collection .add ((T ) createValueOrNull ((Map <String , Object >) rawValue , elementClass , bindingResult , segments ));
222
+ collection .add ((T ) createValueOrNull ((Map <String , Object >) rawValue , elementType , bindingResult , segments ));
222
223
}
223
224
else {
224
225
collection .add ((T ) convertValue (rawValue , elementClass , bindingResult , segments ));
@@ -230,7 +231,7 @@ else if (rawValue instanceof Map) {
230
231
231
232
@ Nullable
232
233
private Object createValueOrNull (
233
- Map <String , Object > rawMap , Class <?> targetType , BindingResult result , Stack <String > segments ) {
234
+ Map <String , Object > rawMap , ResolvableType targetType , BindingResult result , Stack <String > segments ) {
234
235
235
236
try {
236
237
return createValue (rawMap , targetType , result , segments );
@@ -242,11 +243,40 @@ private Object createValueOrNull(
242
243
243
244
@ SuppressWarnings ("unchecked" )
244
245
private Object createValue (
245
- Map <String , Object > rawMap , Class <?> targetType , BindingResult bindingResult ,
246
+ Map <String , Object > rawMap , ResolvableType targetType , BindingResult bindingResult ,
246
247
Stack <String > segments ) throws BindException {
247
248
249
+ Class <?> targetClass = targetType .resolve ();
250
+ Assert .notNull (targetClass , "Unknown target class" );
251
+
252
+ if (Map .class .isAssignableFrom (targetClass )) {
253
+ ResolvableType valueType = targetType .asMap ().getGeneric (1 );
254
+ Class <?> valueClass = valueType .resolve ();
255
+ if (valueClass == null ) {
256
+ bindingResult .rejectValue (toArgumentPath (segments ), "unknownMapValueType" , "Unknown Map value type" );
257
+ return Collections .emptyMap ();
258
+ }
259
+ Map <String , Object > map = CollectionFactory .createMap (targetClass , rawMap .size ());
260
+ for (Map .Entry <String , Object > entry : rawMap .entrySet ()) {
261
+ Object rawValue = entry .getValue ();
262
+ segments .push ("[" + entry .getKey () + "]" );
263
+ if (rawValue == null || valueType .isAssignableFrom (rawValue .getClass ())) {
264
+ map .put (entry .getKey (), entry .getValue ());
265
+ }
266
+ else if (rawValue instanceof Map ) {
267
+ map .put (entry .getKey (), createValueOrNull (
268
+ (Map <String , Object >) rawValue , valueType , bindingResult , segments ));
269
+ }
270
+ else {
271
+ map .put (entry .getKey (), convertValue (rawValue , valueClass , bindingResult , segments ));
272
+ }
273
+ segments .pop ();
274
+ }
275
+ return map ;
276
+ }
277
+
248
278
Object target ;
249
- Constructor <?> ctor = BeanUtils .getResolvableConstructor (targetType );
279
+ Constructor <?> ctor = BeanUtils .getResolvableConstructor (targetClass );
250
280
251
281
// Default constructor + data binding via properties
252
282
@@ -293,7 +323,7 @@ else if (isApproximableCollectionType(rawValue)) {
293
323
}
294
324
else if (rawValue instanceof Map ) {
295
325
boolean isOptional = (paramTypes [i ] == Optional .class );
296
- Class <?> type = ( isOptional ? methodParam .nestedIfOptional (). getNestedParameterType () : paramTypes [ i ] );
326
+ ResolvableType type = ResolvableType . forMethodParameter ( methodParam .nestedIfOptional ());
297
327
Object value = createValueOrNull ((Map <String , Object >) rawValue , type , bindingResult , segments );
298
328
args [i ] = (isOptional ? Optional .ofNullable (value ) : value );
299
329
}
0 commit comments