@@ -937,7 +937,7 @@ else if (Map.class.isAssignableFrom(paramType)) {
937937 value = createMap (paramPath , paramType , resolvableType , valueResolver );
938938 }
939939 else if (paramType .isArray ()) {
940- value = createArray (paramPath , resolvableType , valueResolver );
940+ value = createArray (paramPath , paramType , resolvableType , valueResolver );
941941 }
942942 }
943943
@@ -954,11 +954,9 @@ else if (paramType.isArray()) {
954954 }
955955 }
956956 catch (TypeMismatchException ex ) {
957- ex .initPropertyName (paramPath );
958957 args [i ] = null ;
959958 failedParamNames .add (paramPath );
960- getBindingResult ().recordFieldValue (paramPath , paramType , value );
961- getBindingErrorProcessor ().processPropertyAccessException (ex , getBindingResult ());
959+ handleTypeMismatchException (ex , paramPath , paramType , value );
962960 }
963961 }
964962 }
@@ -1021,27 +1019,29 @@ private boolean hasValuesFor(String paramPath, ValueResolver resolver) {
10211019 return false ;
10221020 }
10231021
1024- @ SuppressWarnings ("unchecked" )
1025- private <V > @ Nullable List <V > createList (
1022+ private @ Nullable List <?> createList (
10261023 String paramPath , Class <?> paramType , ResolvableType type , ValueResolver valueResolver ) {
10271024
10281025 ResolvableType elementType = type .getNested (2 );
10291026 SortedSet <Integer > indexes = getIndexes (paramPath , valueResolver );
10301027 if (indexes == null ) {
10311028 return null ;
10321029 }
1030+
10331031 int size = (indexes .last () < this .autoGrowCollectionLimit ? indexes .last () + 1 : 0 );
1034- List <V > list = (List <V >) CollectionFactory .createCollection (paramType , size );
1032+ List <? > list = (List <? >) CollectionFactory .createCollection (paramType , size );
10351033 for (int i = 0 ; i < size ; i ++) {
10361034 list .add (null );
10371035 }
1036+
10381037 for (int index : indexes ) {
1039- list .set (index , (V ) createObject (elementType , paramPath + "[" + index + "]." , valueResolver ));
1038+ String indexedPath = paramPath + "[" + index + "]" ;
1039+ list .set (index , createIndexedValue (paramPath , paramType , elementType , indexedPath , valueResolver ));
10401040 }
1041+
10411042 return list ;
10421043 }
10431044
1044- @ SuppressWarnings ("unchecked" )
10451045 private <V > @ Nullable Map <String , V > createMap (
10461046 String paramPath , Class <?> paramType , ResolvableType type , ValueResolver valueResolver ) {
10471047
@@ -1051,50 +1051,90 @@ private boolean hasValuesFor(String paramPath, ValueResolver resolver) {
10511051 if (!name .startsWith (paramPath + "[" )) {
10521052 continue ;
10531053 }
1054+
10541055 int startIdx = paramPath .length () + 1 ;
10551056 int endIdx = name .indexOf (']' , startIdx );
1056- String nestedPath = ((name .length () > endIdx + 1 ) ? name .substring (0 , endIdx + 2 ) : "" );
10571057 boolean quoted = (endIdx - startIdx > 2 && name .charAt (startIdx ) == '\'' && name .charAt (endIdx - 1 ) == '\'' );
10581058 String key = (quoted ? name .substring (startIdx + 1 , endIdx - 1 ) : name .substring (startIdx , endIdx ));
1059+
10591060 if (map == null ) {
10601061 map = CollectionFactory .createMap (paramType , 16 );
10611062 }
1062- if (! map . containsKey ( key )) {
1063- map . put ( key , ( V ) createObject ( elementType , nestedPath , valueResolver ) );
1064- }
1063+
1064+ String indexedPath = name . substring ( 0 , endIdx + 1 );
1065+ map . put ( key , createIndexedValue ( paramPath , paramType , elementType , indexedPath , valueResolver ));
10651066 }
1067+
10661068 return map ;
10671069 }
10681070
10691071 @ SuppressWarnings ("unchecked" )
1070- private <V > @ Nullable V @ Nullable [] createArray (String paramPath , ResolvableType type , ValueResolver valueResolver ) {
1072+ private <V > @ Nullable V @ Nullable [] createArray (
1073+ String paramPath , Class <?> paramType , ResolvableType type , ValueResolver valueResolver ) {
1074+
10711075 ResolvableType elementType = type .getNested (2 );
10721076 SortedSet <Integer > indexes = getIndexes (paramPath , valueResolver );
10731077 if (indexes == null ) {
10741078 return null ;
10751079 }
1080+
10761081 int size = (indexes .last () < this .autoGrowCollectionLimit ? indexes .last () + 1 : 0 );
10771082 @ Nullable V [] array = (V []) Array .newInstance (elementType .resolve (), size );
1083+
10781084 for (int index : indexes ) {
1079- array [index ] = (V ) createObject (elementType , paramPath + "[" + index + "]." , valueResolver );
1085+ String indexedPath = paramPath + "[" + index + "]" ;
1086+ array [index ] = createIndexedValue (paramPath , paramType , elementType , indexedPath , valueResolver );
10801087 }
1088+
10811089 return array ;
10821090 }
10831091
10841092 private static @ Nullable SortedSet <Integer > getIndexes (String paramPath , ValueResolver valueResolver ) {
10851093 SortedSet <Integer > indexes = null ;
10861094 for (String name : valueResolver .getNames ()) {
10871095 if (name .startsWith (paramPath + "[" )) {
1088- int endIndex = name .indexOf (']' , paramPath .length () + 1 );
1096+ int endIndex = name .indexOf (']' , paramPath .length () + 2 );
10891097 String rawIndex = name .substring (paramPath .length () + 1 , endIndex );
1090- int index = Integer .parseInt (rawIndex );
1091- indexes = (indexes != null ? indexes : new TreeSet <>());
1092- indexes .add (index );
1098+ if (StringUtils .hasLength (rawIndex )) {
1099+ int index = Integer .parseInt (rawIndex );
1100+ indexes = (indexes != null ? indexes : new TreeSet <>());
1101+ indexes .add (index );
1102+ }
10931103 }
10941104 }
10951105 return indexes ;
10961106 }
10971107
1108+ @ SuppressWarnings ("unchecked" )
1109+ private <V > @ Nullable V createIndexedValue (
1110+ String paramPath , Class <?> paramType , ResolvableType elementType ,
1111+ String indexedPath , ValueResolver valueResolver ) {
1112+
1113+ Object value = null ;
1114+ Class <?> elementClass = elementType .resolve (Object .class );
1115+ Object rawValue = valueResolver .resolveValue (indexedPath , elementClass );
1116+ if (rawValue != null ) {
1117+ try {
1118+ value = convertIfNecessary (rawValue , elementClass );
1119+ }
1120+ catch (TypeMismatchException ex ) {
1121+ handleTypeMismatchException (ex , paramPath , paramType , rawValue );
1122+ }
1123+ }
1124+ else {
1125+ value = createObject (elementType , indexedPath + "." , valueResolver );
1126+ }
1127+ return (V ) value ;
1128+ }
1129+
1130+ private void handleTypeMismatchException (
1131+ TypeMismatchException ex , String paramPath , Class <?> paramType , @ Nullable Object value ) {
1132+
1133+ ex .initPropertyName (paramPath );
1134+ getBindingResult ().recordFieldValue (paramPath , paramType , value );
1135+ getBindingErrorProcessor ().processPropertyAccessException (ex , getBindingResult ());
1136+ }
1137+
10981138 private void validateConstructorArgument (
10991139 Class <?> constructorClass , String nestedPath , @ Nullable String name , @ Nullable Object value ) {
11001140
0 commit comments