diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java b/org.springframework.beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java index 90ae3b5008..93572b3a16 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java @@ -596,7 +596,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra } private PropertyValue createDefaultPropertyValue(PropertyTokenHolder tokens) { - PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(tokens.actualName); + PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(tokens.actualName); Object defaultValue = newValue(pd.getPropertyType(), tokens.canonicalName); return new PropertyValue(tokens.canonicalName, defaultValue); } @@ -615,13 +615,14 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra return Array.newInstance(componentType, 0); } } + else if (Collection.class.isAssignableFrom(type)) { + return CollectionFactory.createCollection(type, 16); + } + else if (Map.class.isAssignableFrom(type)) { + return CollectionFactory.createMap(type, 16); + } else { - if (Collection.class.isAssignableFrom(type)) { - return CollectionFactory.createCollection(type, 16); - } - else { - return type.newInstance(); - } + return type.newInstance(); } } catch (Exception ex) { @@ -791,6 +792,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType); // Pass full property name and old value in here, since we want full // conversion ability for map values. + growMapIfNecessary(map, convertedMapKey, indexedPropertyName, pd, i + 1); value = map.get(convertedMapKey); } else { @@ -844,7 +846,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra return array; } } - + @SuppressWarnings("unchecked") private void growCollectionIfNecessary( Collection collection, int index, String name, PropertyDescriptor pd, int nestingLevel) { @@ -861,7 +863,22 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra } } } - + + @SuppressWarnings("unchecked") + private void growMapIfNecessary( + Map map, Object key, String name, PropertyDescriptor pd, int nestingLevel) { + + if (!this.autoGrowNestedPaths) { + return; + } + if (!map.containsKey(key)) { + Class valueType = GenericCollectionTypeResolver.getMapValueReturnType(pd.getReadMethod(), nestingLevel); + if (valueType != null) { + map.put(key, newValue(valueType, name)); + } + } + } + @Override public void setPropertyValue(String propertyName, Object value) throws BeansException { BeanWrapperImpl nestedBw; diff --git a/org.springframework.beans/src/test/java/org/springframework/beans/BeanWrapperAutoGrowingTests.java b/org.springframework.beans/src/test/java/org/springframework/beans/BeanWrapperAutoGrowingTests.java index 21adde9373..2e554a41eb 100644 --- a/org.springframework.beans/src/test/java/org/springframework/beans/BeanWrapperAutoGrowingTests.java +++ b/org.springframework.beans/src/test/java/org/springframework/beans/BeanWrapperAutoGrowingTests.java @@ -1,15 +1,32 @@ -package org.springframework.beans; +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +package org.springframework.beans; import java.util.List; +import java.util.Map; +import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; +/** + * @author Keith Donald + * @author Juergen Hoeller + */ public class BeanWrapperAutoGrowingTests { Bean bean = new Bean(); @@ -112,6 +129,20 @@ public class BeanWrapperAutoGrowingTests { wrapper.getPropertyValue("listNotParameterized[0]"); } + @Test + public void getPropertyValueAutoGrowMap() { + assertNotNull(wrapper.getPropertyValue("map[A]")); + assertEquals(1, bean.getMap().size()); + assertTrue(bean.getMap().get("A") instanceof Bean); + } + + @Test + public void setPropertyValueAutoGrowMap() { + wrapper.setPropertyValue("map[A].prop", "test"); + assertEquals("test", bean.getMap().get("A").getProp()); + } + + public static class Bean { private String prop; @@ -130,6 +161,8 @@ public class BeanWrapperAutoGrowingTests { private List listNotParameterized; + private Map map; + public String getProp() { return prop; } @@ -182,8 +215,7 @@ public class BeanWrapperAutoGrowingTests { return nestedNoConstructor; } - public void setNestedNoConstructor( - NestedNoDefaultConstructor nestedNoConstructor) { + public void setNestedNoConstructor(NestedNoDefaultConstructor nestedNoConstructor) { this.nestedNoConstructor = nestedNoConstructor; } @@ -195,11 +227,20 @@ public class BeanWrapperAutoGrowingTests { this.listNotParameterized = listNotParameterized; } + public Map getMap() { + return map; + } + + public void setMap(Map map) { + this.map = map; + } } + public static class NestedNoDefaultConstructor { - private NestedNoDefaultConstructor() { + private NestedNoDefaultConstructor() { } } + }