Skip to content

Commit 4591a67

Browse files
committed
Handle [] leniently in constructor binding
See gh-34305
1 parent 9797bc0 commit 4591a67

File tree

2 files changed

+38
-12
lines changed

2 files changed

+38
-12
lines changed

spring-context/src/main/java/org/springframework/validation/DataBinder.java

+27-12
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,10 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter {
142142
*/
143143
protected static final Log logger = LogFactory.getLog(DataBinder.class);
144144

145+
/** Internal constant for constructor binding via "[]". */
146+
private static final int NO_INDEX = -1;
147+
148+
145149
@Nullable
146150
private Object target;
147151

@@ -1056,15 +1060,17 @@ private List<?> createList(
10561060
return null;
10571061
}
10581062

1059-
int size = (indexes.last() < this.autoGrowCollectionLimit ? indexes.last() + 1 : 0);
1063+
int lastIndex = Math.max(indexes.last(), 0);
1064+
int size = (lastIndex < this.autoGrowCollectionLimit ? lastIndex + 1 : 0);
10601065
List<?> list = (List<?>) CollectionFactory.createCollection(paramType, size);
10611066
for (int i = 0; i < size; i++) {
10621067
list.add(null);
10631068
}
10641069

10651070
for (int index : indexes) {
1066-
String indexedPath = paramPath + "[" + index + "]";
1067-
list.set(index, createIndexedValue(paramPath, paramType, elementType, indexedPath, valueResolver));
1071+
String indexedPath = paramPath + "[" + (index != NO_INDEX ? index : "") + "]";
1072+
list.set(Math.max(index, 0),
1073+
createIndexedValue(paramPath, paramType, elementType, indexedPath, valueResolver));
10681074
}
10691075

10701076
return list;
@@ -1108,12 +1114,14 @@ private <V> V[] createArray(
11081114
return null;
11091115
}
11101116

1111-
int size = (indexes.last() < this.autoGrowCollectionLimit ? indexes.last() + 1: 0);
1117+
int lastIndex = Math.max(indexes.last(), 0);
1118+
int size = (lastIndex < this.autoGrowCollectionLimit ? lastIndex + 1: 0);
11121119
V[] array = (V[]) Array.newInstance(elementType.resolve(), size);
11131120

11141121
for (int index : indexes) {
1115-
String indexedPath = paramPath + "[" + index + "]";
1116-
array[index] = createIndexedValue(paramPath, paramType, elementType, indexedPath, valueResolver);
1122+
String indexedPath = paramPath + "[" + (index != NO_INDEX ? index : "") + "]";
1123+
array[Math.max(index, 0)] =
1124+
createIndexedValue(paramPath, paramType, elementType, indexedPath, valueResolver);
11171125
}
11181126

11191127
return array;
@@ -1124,13 +1132,20 @@ private static SortedSet<Integer> getIndexes(String paramPath, ValueResolver val
11241132
SortedSet<Integer> indexes = null;
11251133
for (String name : valueResolver.getNames()) {
11261134
if (name.startsWith(paramPath + "[")) {
1127-
int endIndex = name.indexOf(']', paramPath.length() + 2);
1128-
String rawIndex = name.substring(paramPath.length() + 1, endIndex);
1129-
if (StringUtils.hasLength(rawIndex)) {
1130-
int index = Integer.parseInt(rawIndex);
1131-
indexes = (indexes != null ? indexes : new TreeSet<>());
1132-
indexes.add(index);
1135+
int index;
1136+
if (paramPath.length() + 2 == name.length()) {
1137+
if (!name.endsWith("[]")) {
1138+
continue;
1139+
}
1140+
index = NO_INDEX;
1141+
}
1142+
else {
1143+
int endIndex = name.indexOf(']', paramPath.length() + 2);
1144+
String indexValue = name.substring(paramPath.length() + 1, endIndex);
1145+
index = Integer.parseInt(indexValue);
11331146
}
1147+
indexes = (indexes != null ? indexes : new TreeSet<>());
1148+
indexes.add(index);
11341149
}
11351150
}
11361151
return indexes;

spring-context/src/test/java/org/springframework/validation/DataBinderConstructTests.java

+11
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,17 @@ void simpleListBinding() {
188188
assertThat(target.integerList()).containsExactly(1, 2);
189189
}
190190

191+
@Test
192+
void simpleListBindingEmptyBrackets() {
193+
MapValueResolver valueResolver = new MapValueResolver(Map.of("integerList[]", "1"));
194+
195+
DataBinder binder = initDataBinder(IntegerListRecord.class);
196+
binder.construct(valueResolver);
197+
198+
IntegerListRecord target = getTarget(binder);
199+
assertThat(target.integerList()).containsExactly(1);
200+
}
201+
191202
@Test
192203
void simpleMapBinding() {
193204
MapValueResolver valueResolver = new MapValueResolver(Map.of("integerMap[a]", "1", "integerMap[b]", "2"));

0 commit comments

Comments
 (0)