From e6ce2a3c364d514250e2384c4d03b6f55da3487c Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 2 Jun 2026 17:20:52 +0200 Subject: [PATCH] Expose autoGrowCollectionLimit in ConfigurablePropertyAccessor interface See gh-36862 --- .../AbstractNestablePropertyAccessor.java | 25 +++---------------- .../beans/AbstractPropertyAccessor.java | 12 +++++++++ .../beans/ConfigurablePropertyAccessor.java | 17 ++++++++++++- .../validation/DataBinder.java | 5 ++-- .../validation/DirectFieldBindingResult.java | 3 +-- 5 files changed, 36 insertions(+), 26 deletions(-) diff --git a/spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java b/spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java index 3912156671b..8253a9fe9cd 100644 --- a/spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java +++ b/spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java @@ -76,8 +76,6 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA */ private static final Log logger = LogFactory.getLog(AbstractNestablePropertyAccessor.class); - private int autoGrowCollectionLimit = Integer.MAX_VALUE; - @Nullable Object wrappedObject; private String nestedPath = ""; @@ -156,21 +154,6 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA } - /** - * Specify a limit for array and collection auto-growing. - *

Default is unlimited on a plain accessor. - */ - public void setAutoGrowCollectionLimit(int autoGrowCollectionLimit) { - this.autoGrowCollectionLimit = autoGrowCollectionLimit; - } - - /** - * Return the limit for array and collection auto-growing. - */ - public int getAutoGrowCollectionLimit() { - return this.autoGrowCollectionLimit; - } - /** * Switch the target object, replacing the cached introspection results only * if the class of the new object is different to that of the replaced object. @@ -298,7 +281,7 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA Object convertedValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(), componentType, ph.nested(tokens.keys.length)); int length = Array.getLength(propValue); - if (arrayIndex >= length && arrayIndex < this.autoGrowCollectionLimit) { + if (arrayIndex >= length && arrayIndex < getAutoGrowCollectionLimit()) { Object newArray = Array.newInstance(componentType, arrayIndex + 1); System.arraycopy(propValue, 0, newArray, 0, length); int lastKeyIndex = tokens.canonicalName.lastIndexOf('['); @@ -324,7 +307,7 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA Object convertedValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(), requiredType.getResolvableType().resolve(), requiredType); int size = list.size(); - if (index >= size && index < this.autoGrowCollectionLimit) { + if (index >= size && index < getAutoGrowCollectionLimit()) { for (int i = size; i < index; i++) { try { list.add(null); @@ -761,7 +744,7 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA return array; } int length = Array.getLength(array); - if (index >= length && index < this.autoGrowCollectionLimit) { + if (index >= length && index < getAutoGrowCollectionLimit()) { Class componentType = array.getClass().componentType(); Object newArray = Array.newInstance(componentType, index + 1); System.arraycopy(array, 0, newArray, 0, length); @@ -785,7 +768,7 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA return; } int size = collection.size(); - if (index >= size && index < this.autoGrowCollectionLimit) { + if (index >= size && index < getAutoGrowCollectionLimit()) { Class elementType = ph.getResolvableType().getNested(nestingLevel).asCollection().resolveGeneric(); if (elementType != null) { for (int i = collection.size(); i < index + 1; i++) { diff --git a/spring-beans/src/main/java/org/springframework/beans/AbstractPropertyAccessor.java b/spring-beans/src/main/java/org/springframework/beans/AbstractPropertyAccessor.java index 1bd8b6712e9..7f00c47698d 100644 --- a/spring-beans/src/main/java/org/springframework/beans/AbstractPropertyAccessor.java +++ b/spring-beans/src/main/java/org/springframework/beans/AbstractPropertyAccessor.java @@ -40,6 +40,8 @@ public abstract class AbstractPropertyAccessor extends TypeConverterSupport impl private boolean autoGrowNestedPaths = false; + private int autoGrowCollectionLimit = Integer.MAX_VALUE; + boolean suppressNotWritablePropertyException = false; @@ -63,6 +65,16 @@ public abstract class AbstractPropertyAccessor extends TypeConverterSupport impl return this.autoGrowNestedPaths; } + @Override + public void setAutoGrowCollectionLimit(int autoGrowCollectionLimit) { + this.autoGrowCollectionLimit = autoGrowCollectionLimit; + } + + @Override + public int getAutoGrowCollectionLimit() { + return this.autoGrowCollectionLimit; + } + @Override public void setPropertyValue(PropertyValue pv) throws BeansException { diff --git a/spring-beans/src/main/java/org/springframework/beans/ConfigurablePropertyAccessor.java b/spring-beans/src/main/java/org/springframework/beans/ConfigurablePropertyAccessor.java index f279c2b1e26..bcf6c3c86d2 100644 --- a/spring-beans/src/main/java/org/springframework/beans/ConfigurablePropertyAccessor.java +++ b/spring-beans/src/main/java/org/springframework/beans/ConfigurablePropertyAccessor.java @@ -63,13 +63,28 @@ public interface ConfigurablePropertyAccessor extends PropertyAccessor, Property *

If {@code true}, a {@code null} path location will be populated * with a default object value and traversed instead of resulting in a * {@link NullValueInNestedPathException}. - *

Default is {@code false} on a plain PropertyAccessor instance. + *

Default is {@code false} on a plain accessor. + * @since 4.1 */ void setAutoGrowNestedPaths(boolean autoGrowNestedPaths); /** * Return whether "auto-growing" of nested paths has been activated. + * @since 4.1 */ boolean isAutoGrowNestedPaths(); + /** + * Specify a limit for array and collection auto-growing. + *

Default is unlimited on a plain accessor. + * @since 7.1 + */ + void setAutoGrowCollectionLimit(int autoGrowCollectionLimit); + + /** + * Return the limit for array and collection auto-growing. + * @since 7.1 + */ + int getAutoGrowCollectionLimit(); + } 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 37f93d18224..2174afd37e9 100644 --- a/spring-context/src/main/java/org/springframework/validation/DataBinder.java +++ b/spring-context/src/main/java/org/springframework/validation/DataBinder.java @@ -273,8 +273,9 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter { * Specify the limit for array and collection auto-growing. *

Default is 256, preventing OutOfMemoryErrors in case of large indexes. * Raise this limit if your auto-growing needs are unusually high. - *

Used for setter/field injection via {@link #bind(PropertyValues)}, and not - * applicable to constructor binding via {@link #construct}. + *

Used for setter injection - and as of 7.1 also for field injection - + * via {@link #bind(PropertyValues)}; not applicable to constructor binding + * via {@link #construct}. * @see #initBeanPropertyAccess() * @see org.springframework.beans.BeanWrapper#setAutoGrowCollectionLimit */ diff --git a/spring-context/src/main/java/org/springframework/validation/DirectFieldBindingResult.java b/spring-context/src/main/java/org/springframework/validation/DirectFieldBindingResult.java index 68f7537354c..54e5b9616a0 100644 --- a/spring-context/src/main/java/org/springframework/validation/DirectFieldBindingResult.java +++ b/spring-context/src/main/java/org/springframework/validation/DirectFieldBindingResult.java @@ -19,7 +19,6 @@ package org.springframework.validation; import org.jspecify.annotations.Nullable; import org.springframework.beans.ConfigurablePropertyAccessor; -import org.springframework.beans.DirectFieldAccessor; import org.springframework.beans.PropertyAccessorFactory; /** @@ -100,7 +99,7 @@ public class DirectFieldBindingResult extends AbstractPropertyBindingResult { this.directFieldAccessor = createDirectFieldAccessor(); this.directFieldAccessor.setExtractOldValueForEditor(true); this.directFieldAccessor.setAutoGrowNestedPaths(this.autoGrowNestedPaths); - ((DirectFieldAccessor) this.directFieldAccessor).setAutoGrowCollectionLimit(this.autoGrowCollectionLimit); + this.directFieldAccessor.setAutoGrowCollectionLimit(this.autoGrowCollectionLimit); } return this.directFieldAccessor; }