@@ -937,7 +937,7 @@ else if (Map.class.isAssignableFrom(paramType)) {
937
937
value = createMap (paramPath , paramType , resolvableType , valueResolver );
938
938
}
939
939
else if (paramType .isArray ()) {
940
- value = createArray (paramPath , resolvableType , valueResolver );
940
+ value = createArray (paramPath , paramType , resolvableType , valueResolver );
941
941
}
942
942
}
943
943
@@ -954,11 +954,9 @@ else if (paramType.isArray()) {
954
954
}
955
955
}
956
956
catch (TypeMismatchException ex ) {
957
- ex .initPropertyName (paramPath );
958
957
args [i ] = null ;
959
958
failedParamNames .add (paramPath );
960
- getBindingResult ().recordFieldValue (paramPath , paramType , value );
961
- getBindingErrorProcessor ().processPropertyAccessException (ex , getBindingResult ());
959
+ handleTypeMismatchException (ex , paramPath , paramType , value );
962
960
}
963
961
}
964
962
}
@@ -1021,27 +1019,29 @@ private boolean hasValuesFor(String paramPath, ValueResolver resolver) {
1021
1019
return false ;
1022
1020
}
1023
1021
1024
- @ SuppressWarnings ("unchecked" )
1025
- private <V > @ Nullable List <V > createList (
1022
+ private @ Nullable List <?> createList (
1026
1023
String paramPath , Class <?> paramType , ResolvableType type , ValueResolver valueResolver ) {
1027
1024
1028
1025
ResolvableType elementType = type .getNested (2 );
1029
1026
SortedSet <Integer > indexes = getIndexes (paramPath , valueResolver );
1030
1027
if (indexes == null ) {
1031
1028
return null ;
1032
1029
}
1030
+
1033
1031
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 );
1035
1033
for (int i = 0 ; i < size ; i ++) {
1036
1034
list .add (null );
1037
1035
}
1036
+
1038
1037
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 ));
1040
1040
}
1041
+
1041
1042
return list ;
1042
1043
}
1043
1044
1044
- @ SuppressWarnings ("unchecked" )
1045
1045
private <V > @ Nullable Map <String , V > createMap (
1046
1046
String paramPath , Class <?> paramType , ResolvableType type , ValueResolver valueResolver ) {
1047
1047
@@ -1051,50 +1051,90 @@ private boolean hasValuesFor(String paramPath, ValueResolver resolver) {
1051
1051
if (!name .startsWith (paramPath + "[" )) {
1052
1052
continue ;
1053
1053
}
1054
+
1054
1055
int startIdx = paramPath .length () + 1 ;
1055
1056
int endIdx = name .indexOf (']' , startIdx );
1056
- String nestedPath = ((name .length () > endIdx + 1 ) ? name .substring (0 , endIdx + 2 ) : "" );
1057
1057
boolean quoted = (endIdx - startIdx > 2 && name .charAt (startIdx ) == '\'' && name .charAt (endIdx - 1 ) == '\'' );
1058
1058
String key = (quoted ? name .substring (startIdx + 1 , endIdx - 1 ) : name .substring (startIdx , endIdx ));
1059
+
1059
1060
if (map == null ) {
1060
1061
map = CollectionFactory .createMap (paramType , 16 );
1061
1062
}
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 ));
1065
1066
}
1067
+
1066
1068
return map ;
1067
1069
}
1068
1070
1069
1071
@ 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
+
1071
1075
ResolvableType elementType = type .getNested (2 );
1072
1076
SortedSet <Integer > indexes = getIndexes (paramPath , valueResolver );
1073
1077
if (indexes == null ) {
1074
1078
return null ;
1075
1079
}
1080
+
1076
1081
int size = (indexes .last () < this .autoGrowCollectionLimit ? indexes .last () + 1 : 0 );
1077
1082
@ Nullable V [] array = (V []) Array .newInstance (elementType .resolve (), size );
1083
+
1078
1084
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 );
1080
1087
}
1088
+
1081
1089
return array ;
1082
1090
}
1083
1091
1084
1092
private static @ Nullable SortedSet <Integer > getIndexes (String paramPath , ValueResolver valueResolver ) {
1085
1093
SortedSet <Integer > indexes = null ;
1086
1094
for (String name : valueResolver .getNames ()) {
1087
1095
if (name .startsWith (paramPath + "[" )) {
1088
- int endIndex = name .indexOf (']' , paramPath .length () + 1 );
1096
+ int endIndex = name .indexOf (']' , paramPath .length () + 2 );
1089
1097
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
+ }
1093
1103
}
1094
1104
}
1095
1105
return indexes ;
1096
1106
}
1097
1107
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
+
1098
1138
private void validateConstructorArgument (
1099
1139
Class <?> constructorClass , String nestedPath , @ Nullable String name , @ Nullable Object value ) {
1100
1140
0 commit comments