From 4350fc21b3cb30bd09288d8323b4bc4fcd5a3de7 Mon Sep 17 00:00:00 2001 From: rstoyanchev Date: Mon, 30 Dec 2024 10:46:40 +0000 Subject: [PATCH] List constructor arg initialized correctly DataBinder now uses the calculated List size rather than the number of indexes to initialize the list. Closes gh-34145 --- .../springframework/validation/DataBinder.java | 4 +++- .../validation/DataBinderConstructTests.java | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/spring-context/src/main/java/org/springframework/validation/DataBinder.java b/spring-context/src/main/java/org/springframework/validation/DataBinder.java index 3e9c9893ed2..274331a89c8 100644 --- a/spring-context/src/main/java/org/springframework/validation/DataBinder.java +++ b/spring-context/src/main/java/org/springframework/validation/DataBinder.java @@ -1060,7 +1060,9 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter { } int size = (indexes.last() < this.autoGrowCollectionLimit ? indexes.last() + 1 : 0); List list = (List) CollectionFactory.createCollection(paramType, size); - indexes.forEach(i -> list.add(null)); + for (int i = 0; i < size; i++) { + list.add(null); + } for (int index : indexes) { list.set(index, (V) createObject(elementType, paramPath + "[" + index + "].", valueResolver)); } diff --git a/spring-context/src/test/java/org/springframework/validation/DataBinderConstructTests.java b/spring-context/src/test/java/org/springframework/validation/DataBinderConstructTests.java index 48166432708..c4ee77a6f90 100644 --- a/spring-context/src/test/java/org/springframework/validation/DataBinderConstructTests.java +++ b/spring-context/src/test/java/org/springframework/validation/DataBinderConstructTests.java @@ -121,6 +121,24 @@ class DataBinderConstructTests { assertThat(list.get(2).param1()).isEqualTo("value3"); } + @Test // gh-34145 + void listBindingWithNonconsecutiveIndices() { + MapValueResolver valueResolver = new MapValueResolver(Map.of( + "dataClassList[0].param1", "value1", "dataClassList[0].param2", "true", + "dataClassList[1].param1", "value2", "dataClassList[1].param2", "true", + "dataClassList[3].param1", "value3", "dataClassList[3].param2", "true")); + + DataBinder binder = initDataBinder(ListDataClass.class); + binder.construct(valueResolver); + + ListDataClass dataClass = getTarget(binder); + List list = dataClass.dataClassList(); + + assertThat(list.get(0).param1()).isEqualTo("value1"); + assertThat(list.get(1).param1()).isEqualTo("value2"); + assertThat(list.get(3).param1()).isEqualTo("value3"); + } + @Test void mapBinding() { MapValueResolver valueResolver = new MapValueResolver(Map.of(