From aa213396b4aa73501d44927d3fe016571bba7555 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 11 Feb 2015 11:29:15 +0100 Subject: [PATCH] BeanWrapper auto-grows arrays if necessary Previously, only indexed access for collections were supported. When attempting to access the element of an array that had not the requested size, the call would fail with an IndexOutOfBoundException This commit harmonize the binding support so that the array is updated according to the requested index if necessary. Issue: SPR-12706 --- .../beans/BeanWrapperImpl.java | 11 ++++- .../beans/BeanWrapperTests.java | 46 ++++++++++++++++++- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/spring-beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java b/spring-beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java index 95d79fe711d..76af626a73d 100644 --- a/spring-beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java +++ b/spring-beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -78,6 +78,7 @@ import org.springframework.util.StringUtils; * @author Rod Johnson * @author Juergen Hoeller * @author Rob Harrop + * @author Stephane Nicoll * @since 15 April 2001 * @see #registerCustomEditor * @see #setPropertyValues @@ -978,6 +979,14 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra } Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType, TypeDescriptor.nested(property(pd), tokens.keys.length)); + int length = Array.getLength(propValue); + if (arrayIndex >= length && arrayIndex < this.autoGrowCollectionLimit) { + Class componentType = propValue.getClass().getComponentType(); + Object newArray = Array.newInstance(componentType, arrayIndex + 1); + System.arraycopy(propValue, 0, newArray, 0, length); + setPropertyValue(actualName, newArray); + propValue = getPropertyValue(actualName); + } Array.set(propValue, arrayIndex, convertedValue); } catch (IndexOutOfBoundsException ex) { diff --git a/spring-beans/src/test/java/org/springframework/beans/BeanWrapperTests.java b/spring-beans/src/test/java/org/springframework/beans/BeanWrapperTests.java index 895ffd38933..ccd56d0e46e 100644 --- a/spring-beans/src/test/java/org/springframework/beans/BeanWrapperTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/BeanWrapperTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -518,6 +518,36 @@ public final class BeanWrapperTests extends AbstractConfigurablePropertyAccessor assertTrue("correct values", pt.stringArray[0].equals("a1") && pt.stringArray[1].equals("b2")); } + @Test + public void testStringArrayAutoGrow() throws Exception { + StringArrayBean target = new StringArrayBean(); + BeanWrapper bw = new BeanWrapperImpl(target); + bw.setAutoGrowNestedPaths(true); + + bw.setPropertyValue("array[0]", "Test0"); + assertEquals(1, target.getArray().length); + + bw.setPropertyValue("array[2]", "Test2"); + assertEquals(3, target.getArray().length); + assertTrue("correct values", target.getArray()[0].equals("Test0") && target.getArray()[1] == null && + target.getArray()[2].equals("Test2")); + } + + @Test + public void testPrimitiveArrayAutoGrow() throws Exception { + PrimitiveArrayBean target = new PrimitiveArrayBean(); + BeanWrapper bw = new BeanWrapperImpl(target); + bw.setAutoGrowNestedPaths(true); + + bw.setPropertyValue("array[0]", 1); + assertEquals(1, target.getArray().length); + + bw.setPropertyValue("array[2]", 3); + assertEquals(3, target.getArray().length); + assertTrue("correct values", target.getArray()[0] == 1 && target.getArray()[1] == 0 && + target.getArray()[2] == 3); + } + @Test public void testStringPropertyWithCustomEditor() throws Exception { TestBean tb = new TestBean(); @@ -1723,6 +1753,20 @@ public final class BeanWrapperTests extends AbstractConfigurablePropertyAccessor } } + @SuppressWarnings("unused") + private static class StringArrayBean { + + private String[] array; + + public String[] getArray() { + return array; + } + + public void setArray(String[] array) { + this.array = array; + } + } + @SuppressWarnings("unused") private static class NumberPropertyBean {