@@ -149,7 +149,7 @@ public Object bind(
149
149
150
150
if (isApproximableCollectionType (rawValue )) {
151
151
segments .push (argumentName );
152
- return createCollection ((Collection <Object >) rawValue , targetType , bindingResult , segments );
152
+ return bindCollection ((Collection <Object >) rawValue , targetType , bindingResult , segments );
153
153
}
154
154
155
155
if (targetClass == Optional .class ) {
@@ -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 , targetType , bindingResult , segments );
163
+ Object target = bindMap ((Map <String , Object >) rawValue , targetType , bindingResult , segments );
164
164
return wrapAsOptionalIfNecessary (target , targetType );
165
165
}
166
166
@@ -195,7 +195,7 @@ private boolean isApproximableCollectionType(@Nullable Object rawValue) {
195
195
}
196
196
197
197
@ SuppressWarnings ({"ConstantConditions" , "unchecked" })
198
- private <T > Collection <T > createCollection (
198
+ private <T > Collection <T > bindCollection (
199
199
Collection <Object > rawCollection , ResolvableType collectionType ,
200
200
BindingResult bindingResult , Stack <String > segments ) {
201
201
@@ -219,7 +219,7 @@ private <T> Collection<T> createCollection(
219
219
collection .add ((T ) rawValue );
220
220
}
221
221
else if (rawValue instanceof Map ) {
222
- collection .add ((T ) createValueOrNull ((Map <String , Object >) rawValue , elementType , bindingResult , segments ));
222
+ collection .add ((T ) bindMap ((Map <String , Object >) rawValue , elementType , bindingResult , segments ));
223
223
}
224
224
else {
225
225
collection .add ((T ) convertValue (rawValue , elementClass , bindingResult , segments ));
@@ -230,134 +230,128 @@ else if (rawValue instanceof Map) {
230
230
}
231
231
232
232
@ Nullable
233
- private Object createValueOrNull (
234
- Map <String , Object > rawMap , ResolvableType targetType , BindingResult result , Stack <String > segments ) {
235
-
236
- try {
237
- return createValue (rawMap , targetType , result , segments );
238
- }
239
- catch (BindException ex ) {
240
- return null ;
241
- }
242
- }
243
-
244
233
@ SuppressWarnings ("unchecked" )
245
- private Object createValue (
234
+ private Object bindMap (
246
235
Map <String , Object > rawMap , ResolvableType targetType , BindingResult bindingResult ,
247
- Stack <String > segments ) throws BindException {
236
+ Stack <String > segments ) {
248
237
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 ));
238
+ try {
239
+ Class <?> targetClass = targetType .resolve ();
240
+ Assert .notNull (targetClass , "Unknown target class" );
241
+
242
+ if (Map .class .isAssignableFrom (targetClass )) {
243
+ ResolvableType valueType = targetType .asMap ().getGeneric (1 );
244
+ Class <?> valueClass = valueType .resolve ();
245
+ if (valueClass == null ) {
246
+ bindingResult .rejectValue (toArgumentPath (segments ), "unknownMapValueType" , "Unknown Map value type" );
247
+ return Collections .emptyMap ();
269
248
}
270
- else {
271
- map .put (entry .getKey (), convertValue (rawValue , valueClass , bindingResult , segments ));
249
+ Map <String , Object > map = CollectionFactory .createMap (targetClass , rawMap .size ());
250
+ for (Map .Entry <String , Object > entry : rawMap .entrySet ()) {
251
+ Object rawValue = entry .getValue ();
252
+ segments .push ("[" + entry .getKey () + "]" );
253
+ if (rawValue == null || valueType .isAssignableFrom (rawValue .getClass ())) {
254
+ map .put (entry .getKey (), entry .getValue ());
255
+ }
256
+ else if (rawValue instanceof Map ) {
257
+ map .put (entry .getKey (), bindMap (
258
+ (Map <String , Object >) rawValue , valueType , bindingResult , segments ));
259
+ }
260
+ else {
261
+ map .put (entry .getKey (), convertValue (rawValue , valueClass , bindingResult , segments ));
262
+ }
263
+ segments .pop ();
272
264
}
273
- segments . pop () ;
265
+ return map ;
274
266
}
275
- return map ;
276
- }
277
-
278
- Object target ;
279
- Constructor <?> ctor = BeanUtils .getResolvableConstructor (targetClass );
280
267
281
- // Default constructor + data binding via properties
268
+ Object target ;
269
+ Constructor <?> ctor = BeanUtils .getResolvableConstructor (targetClass );
282
270
283
- if (ctor .getParameterCount () == 0 ) {
284
- target = BeanUtils .instantiateClass (ctor );
285
- DataBinder dataBinder = new DataBinder (target );
286
- initDataBinder (dataBinder );
287
- dataBinder .getBindingResult ().setNestedPath (toArgumentPath (segments ));
288
- dataBinder .setConversionService (getConversionService ());
289
- dataBinder .bind (initBindValues (rawMap ));
271
+ // Default constructor + data binding via properties
290
272
291
- if (dataBinder .getBindingResult ().hasErrors ()) {
292
- addErrors (dataBinder , bindingResult , segments );
293
- throw new BindException (bindingResult );
294
- }
273
+ if (ctor .getParameterCount () == 0 ) {
274
+ target = BeanUtils .instantiateClass (ctor );
275
+ DataBinder dataBinder = new DataBinder (target );
276
+ initDataBinder (dataBinder );
277
+ dataBinder .getBindingResult ().setNestedPath (toArgumentPath (segments ));
278
+ dataBinder .setConversionService (getConversionService ());
279
+ dataBinder .bind (toPropertyValues (rawMap ));
295
280
296
- return target ;
297
- }
281
+ if (dataBinder .getBindingResult ().hasErrors ()) {
282
+ addDataBinderErrors (dataBinder , bindingResult , segments );
283
+ throw new BindException (bindingResult );
284
+ }
298
285
299
- // Data class constructor
286
+ return target ;
287
+ }
300
288
301
- if (!segments .isEmpty ()) {
302
- segments .push ("." );
303
- }
289
+ // Data class constructor
304
290
305
- String [] paramNames = BeanUtils .getParameterNames (ctor );
306
- Class <?>[] paramTypes = ctor .getParameterTypes ();
307
- Object [] args = new Object [paramTypes .length ];
308
-
309
- for (int i = 0 ; i < paramNames .length ; i ++) {
310
- String paramName = paramNames [i ];
311
- Object rawValue = rawMap .get (paramName );
312
- segments .push (paramName );
313
- MethodParameter methodParam = new MethodParameter (ctor , i );
314
- if (rawValue == null && methodParam .isOptional ()) {
315
- args [i ] = (paramTypes [i ] == Optional .class ? Optional .empty () : null );
291
+ if (!segments .isEmpty ()) {
292
+ segments .push ("." );
316
293
}
317
- else if (paramTypes [i ] == Object .class ) {
318
- args [i ] = rawValue ;
294
+
295
+ String [] paramNames = BeanUtils .getParameterNames (ctor );
296
+ Class <?>[] paramTypes = ctor .getParameterTypes ();
297
+ Object [] args = new Object [paramTypes .length ];
298
+
299
+ for (int i = 0 ; i < paramNames .length ; i ++) {
300
+ String paramName = paramNames [i ];
301
+ Object rawValue = rawMap .get (paramName );
302
+ segments .push (paramName );
303
+ MethodParameter methodParam = new MethodParameter (ctor , i );
304
+ if (rawValue == null && methodParam .isOptional ()) {
305
+ args [i ] = (paramTypes [i ] == Optional .class ? Optional .empty () : null );
306
+ }
307
+ else if (paramTypes [i ] == Object .class ) {
308
+ args [i ] = rawValue ;
309
+ }
310
+ else if (isApproximableCollectionType (rawValue )) {
311
+ ResolvableType elementType = ResolvableType .forMethodParameter (methodParam );
312
+ args [i ] = bindCollection ((Collection <Object >) rawValue , elementType , bindingResult , segments );
313
+ }
314
+ else if (rawValue instanceof Map ) {
315
+ boolean isOptional = (paramTypes [i ] == Optional .class );
316
+ ResolvableType type = ResolvableType .forMethodParameter (methodParam .nestedIfOptional ());
317
+ Object value = bindMap ((Map <String , Object >) rawValue , type , bindingResult , segments );
318
+ args [i ] = (isOptional ? Optional .ofNullable (value ) : value );
319
+ }
320
+ else {
321
+ args [i ] = convertValue (rawValue , paramTypes [i ], new TypeDescriptor (methodParam ), bindingResult , segments );
322
+ }
323
+ segments .pop ();
319
324
}
320
- else if ( isApproximableCollectionType ( rawValue )) {
321
- ResolvableType elementType = ResolvableType . forMethodParameter ( methodParam );
322
- args [ i ] = createCollection (( Collection < Object >) rawValue , elementType , bindingResult , segments );
325
+
326
+ if ( segments . size () > 1 ) {
327
+ segments . pop ( );
323
328
}
324
- else if (rawValue instanceof Map ) {
325
- boolean isOptional = (paramTypes [i ] == Optional .class );
326
- ResolvableType type = ResolvableType .forMethodParameter (methodParam .nestedIfOptional ());
327
- Object value = createValueOrNull ((Map <String , Object >) rawValue , type , bindingResult , segments );
328
- args [i ] = (isOptional ? Optional .ofNullable (value ) : value );
329
+
330
+ try {
331
+ return BeanUtils .instantiateClass (ctor , args );
329
332
}
330
- else {
331
- args [i ] = convertValue (rawValue , paramTypes [i ], new TypeDescriptor (methodParam ), bindingResult , segments );
333
+ catch (BeanInstantiationException ex ) {
334
+ // Swallow if we had binding errors, it's as far as we could go
335
+ checkBindingResult (bindingResult );
336
+ throw ex ;
332
337
}
333
- segments .pop ();
334
- }
335
-
336
- if (segments .size () > 1 ) {
337
- segments .pop ();
338
338
}
339
-
340
- try {
341
- return BeanUtils .instantiateClass (ctor , args );
342
- }
343
- catch (BeanInstantiationException ex ) {
344
- // Swallow if we had binding errors, it's as far as we could go
345
- checkBindingResult (bindingResult );
346
- throw ex ;
339
+ catch (BindException ex ) {
340
+ return null ;
347
341
}
348
342
}
349
343
350
- private MutablePropertyValues initBindValues (Map <String , Object > rawMap ) {
344
+ private static MutablePropertyValues toPropertyValues (Map <String , Object > rawMap ) {
351
345
MutablePropertyValues mpvs = new MutablePropertyValues ();
352
346
Stack <String > segments = new Stack <>();
353
347
for (String key : rawMap .keySet ()) {
354
- addBindValues (mpvs , key , rawMap .get (key ), segments );
348
+ addPropertyValue (mpvs , key , rawMap .get (key ), segments );
355
349
}
356
350
return mpvs ;
357
351
}
358
352
359
353
@ SuppressWarnings ("unchecked" )
360
- private void addBindValues (MutablePropertyValues mpvs , String name , Object value , Stack <String > segments ) {
354
+ private static void addPropertyValue (MutablePropertyValues mpvs , String name , Object value , Stack <String > segments ) {
361
355
if (value instanceof List ) {
362
356
List <Object > items = (List <Object >) value ;
363
357
if (items .isEmpty ()) {
@@ -367,15 +361,15 @@ private void addBindValues(MutablePropertyValues mpvs, String name, Object value
367
361
}
368
362
else {
369
363
for (int i = 0 ; i < items .size (); i ++) {
370
- addBindValues (mpvs , name + "[" + i + "]" , items .get (i ), segments );
364
+ addPropertyValue (mpvs , name + "[" + i + "]" , items .get (i ), segments );
371
365
}
372
366
}
373
367
}
374
368
else if (value instanceof Map ) {
375
369
segments .push (name + "." );
376
370
Map <String , Object > map = (Map <String , Object >) value ;
377
371
for (String key : map .keySet ()) {
378
- addBindValues (mpvs , key , map .get (key ), segments );
372
+ addPropertyValue (mpvs , key , map .get (key ), segments );
379
373
}
380
374
segments .pop ();
381
375
}
@@ -386,7 +380,7 @@ else if (value instanceof Map) {
386
380
}
387
381
}
388
382
389
- private String toArgumentPath (Stack <String > path ) {
383
+ private static String toArgumentPath (Stack <String > path ) {
390
384
StringBuilder sb = new StringBuilder ();
391
385
path .forEach (sb ::append );
392
386
return sb .toString ();
@@ -415,7 +409,7 @@ private Object convertValue(
415
409
return null ;
416
410
}
417
411
418
- private void addErrors (DataBinder binder , BindingResult bindingResult , Stack <String > segments ) {
412
+ private static void addDataBinderErrors (DataBinder binder , BindingResult bindingResult , Stack <String > segments ) {
419
413
String path = (!segments .isEmpty () ? toArgumentPath (segments ) + "." : "" );
420
414
binder .getBindingResult ().getFieldErrors ().forEach (error -> bindingResult .addError (
421
415
new FieldError (bindingResult .getObjectName (), path + error .getField (),
0 commit comments