mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-17 08:24:13 +00:00
Check list index after auto-grow in AbstractNestablePropertyAccessor
Prior to this commit, the List branch in AbstractNestablePropertyAccessor's getPropertyValue() method called list.get(index) unconditionally after invoking growCollectionIfNecessary(), which implicitly relied on the list throwing an IndexOutOfBoundsException for out-of-range access. Such an exception is caught downstream and wrapped as an InvalidPropertyException; however, any List implementation whose get() method allocates elements on demand rather than throwing an IndexOutOfBoundsException could bypass that check. This behavior was also inconsistent with the Collection/Iterable branch in the same method, which already performs an explicit `index >= collection.size()` bounds check before attempting element access. To address that, this commit aligns the List branch with the Collection/Iterable branch by adding an explicit `index < 0 || index >= list.size()` check immediately after the auto-grow attempt. If the index remains out of bounds after growCollectionIfNecessary() runs – for example, because growth was capped by autoGrowCollectionLimit or auto-growing was disabled – an InvalidPropertyException is now thrown rather than delegating to list.get() which may or may not throw an exception. Closes gh-37036
This commit is contained in:
committed by
Brian Clozel
parent
ac0f8be0d8
commit
d186b381b9
+5
@@ -649,6 +649,11 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
|
||||
else if (value instanceof List list) {
|
||||
int index = Integer.parseInt(key);
|
||||
growCollectionIfNecessary(list, index, indexedPropertyName.toString(), ph, i + 1);
|
||||
if (index < 0 || index >= list.size()) {
|
||||
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
|
||||
"Cannot get element with index " + index + " from List of size " +
|
||||
list.size() + ", accessed using property path '" + propertyName + "'");
|
||||
}
|
||||
value = list.get(index);
|
||||
}
|
||||
else if (value instanceof Map map) {
|
||||
|
||||
+49
-1
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.beans;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -183,7 +184,34 @@ class BeanWrapperAutoGrowingTests {
|
||||
wrapper.setAutoGrowCollectionLimit(2);
|
||||
assertThatExceptionOfType(InvalidPropertyException.class)
|
||||
.isThrownBy(() -> wrapper.getPropertyValue("list[4]"))
|
||||
.withRootCauseInstanceOf(IndexOutOfBoundsException.class);
|
||||
.withMessageContainingAll(
|
||||
"Invalid property 'list[4]'",
|
||||
"Cannot get element with index 4 from List of size 0");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getPropertyValueSelfPopulatingListWorksWithinLimit() {
|
||||
bean.setList(new SelfPopulatingList());
|
||||
assertThat(wrapper.getPropertyValue("list[2]")).isInstanceOf(Bean.class);
|
||||
assertThat(bean.getList())
|
||||
.hasSize(3)
|
||||
.allSatisfy(entry -> assertThat(entry).isInstanceOf(Bean.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getPropertyValueSelfPopulatingListFailsAgainstLimit() {
|
||||
bean.setList(new SelfPopulatingList());
|
||||
wrapper.setAutoGrowCollectionLimit(2);
|
||||
assertThatExceptionOfType(InvalidPropertyException.class)
|
||||
.isThrownBy(() -> wrapper.getPropertyValue("list[4]"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void setPropertyValueSelfPopulatingListFailsAgainstLimitForNestedPath() {
|
||||
bean.setList(new SelfPopulatingList());
|
||||
wrapper.setAutoGrowCollectionLimit(2);
|
||||
assertThatExceptionOfType(InvalidPropertyException.class)
|
||||
.isThrownBy(() -> wrapper.setPropertyValue("list[4].prop", "test"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -382,4 +410,24 @@ class BeanWrapperAutoGrowingTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A {@link List} implementation that creates elements on demand in {@link #get(int)}
|
||||
* instead of throwing {@link IndexOutOfBoundsException} for out-of-range indexes.
|
||||
*
|
||||
* <p>Used to verify that {@link BeanWrapperImpl} does not delegate to
|
||||
* {@link List#get(int)} for indexes beyond the configured auto-grow limit.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
private static class SelfPopulatingList extends ArrayList<Bean> {
|
||||
|
||||
@Override
|
||||
public Bean get(int index) {
|
||||
while (size() <= index) {
|
||||
add(new Bean());
|
||||
}
|
||||
return super.get(index);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user