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 35b41881a82..c13f8d83ae3 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 @@ -787,8 +787,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra Class mapKeyType = GenericCollectionTypeResolver.getMapKeyReturnType(pd.getReadMethod(), i + 1); // IMPORTANT: Do not pass full property name in here - property editors // must not kick in for map keys but rather only for map values. - Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType, - new PropertyTypeDescriptor(mapKeyType, new MethodParameter(pd.getReadMethod(), -1), pd)); + TypeDescriptor typeDescriptor = mapKeyType != null ? TypeDescriptor.valueOf(mapKeyType) : TypeDescriptor.valueOf(Object.class); + Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType, typeDescriptor); value = map.get(convertedMapKey); } else { @@ -935,8 +935,10 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra if (isExtractOldValueForEditor()) { oldValue = Array.get(propValue, arrayIndex); } + MethodParameter methodParameter = new MethodParameter(pd.getReadMethod(), -1); + methodParameter.increaseNestingLevel(); Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType, - new PropertyTypeDescriptor(requiredType, new MethodParameter(pd.getReadMethod(), -1), pd)); + new PropertyTypeDescriptor(requiredType, methodParameter, pd)); Array.set(propValue, arrayIndex, convertedValue); } catch (IndexOutOfBoundsException ex) { @@ -954,8 +956,10 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra if (isExtractOldValueForEditor() && index < list.size()) { oldValue = list.get(index); } + MethodParameter methodParameter = new MethodParameter(pd.getReadMethod(), -1); + methodParameter.increaseNestingLevel(); Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType, - new PropertyTypeDescriptor(requiredType, new MethodParameter(pd.getReadMethod(), -1), pd)); + new PropertyTypeDescriptor(requiredType, methodParameter, pd)); if (index < list.size()) { list.set(index, convertedValue); } @@ -983,17 +987,19 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra Map map = (Map) propValue; // IMPORTANT: Do not pass full property name in here - property editors // must not kick in for map keys but rather only for map values. - Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType, - new PropertyTypeDescriptor(mapKeyType, new MethodParameter(pd.getReadMethod(), -1), pd)); + TypeDescriptor typeDescriptor = mapKeyType != null ? TypeDescriptor.valueOf(mapKeyType) : TypeDescriptor.valueOf(Object.class); + Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType, typeDescriptor); Object oldValue = null; if (isExtractOldValueForEditor()) { oldValue = map.get(convertedMapKey); } // Pass full property name and old value in here, since we want full // conversion ability for map values. + MethodParameter methodParameter = new MethodParameter(pd.getReadMethod(), -1); + methodParameter.increaseNestingLevel(); Object convertedMapValue = convertIfNecessary( propertyName, oldValue, pv.getValue(), mapValueType, - new TypeDescriptor(new MethodParameter(pd.getReadMethod(), -1, tokens.keys.length + 1))); + new PropertyTypeDescriptor(mapValueType, methodParameter, pd)); map.put(convertedMapKey, convertedMapValue); } else { diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/Spr7839Tests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/Spr7839Tests.java index d3d98dfcf13..b61759a9a11 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/Spr7839Tests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/Spr7839Tests.java @@ -2,6 +2,7 @@ package org.springframework.web.servlet.mvc.annotation; import static org.junit.Assert.assertEquals; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -70,7 +71,6 @@ public class Spr7839Tests { } @Test - @Ignore public void listOfLists() throws Exception { request.setRequestURI("/nested/listOfLists"); request.addParameter("nested.listOfLists[0]", "Nested1,Nested2"); @@ -91,6 +91,15 @@ public class Spr7839Tests { adapter.handle(request, response, controller); } + @Test + @Ignore + public void arrayOfLists() throws Exception { + // TODO two issues here: no autogrow for array properties, and GenericCollectionResolver not capable of accessing nested element type + request.setRequestURI("/nested/arrayOfLists"); + request.addParameter("nested.arrayOfLists[0]", "Nested1,Nested2"); + adapter.handle(request, response, controller); + } + @Test @Ignore public void map() throws Exception { @@ -99,6 +108,13 @@ public class Spr7839Tests { adapter.handle(request, response, controller); } + @Test + public void mapOfLists() throws Exception { + request.setRequestURI("/nested/mapOfLists"); + request.addParameter("nested.mapOfLists['apples'][0]", "1"); + adapter.handle(request, response, controller); + } + @Controller public static class Spr7839Controller { @@ -112,11 +128,6 @@ public class Spr7839Tests { assertEquals("Nested2", bean.nested.list.get(1).foo); } - @RequestMapping("/nested/map") - public void handlerMap(JavaBean bean) { - assertEquals("bar", bean.nested.map.get("apple").foo); - } - @RequestMapping("/nested/listElement") public void handlerListElement(JavaBean bean) { assertEquals("Nested", bean.nested.list.get(0).foo); @@ -132,6 +143,22 @@ public class Spr7839Tests { assertEquals("Nested", bean.nested.listOfLists.get(0).get(0).foo); } + @RequestMapping("/nested/arrayOfLists") + public void handlerArrayOfLists(JavaBean bean) { + System.out.println(bean.nested.arrayOfLists[0].get(1).getClass()); + assertEquals("Nested2", bean.nested.arrayOfLists[0].get(1).foo); + } + + @RequestMapping("/nested/map") + public void handlerMap(JavaBean bean) { + assertEquals("bar", bean.nested.map.get("apple").foo); + } + + @RequestMapping("/nested/mapOfLists") + public void handlerMapOfLists(JavaBean bean) { + assertEquals(new Integer(1), bean.nested.mapOfLists.get("apples").get(0)); + } + } public static class JavaBean { @@ -157,10 +184,14 @@ public class Spr7839Tests { private List> listOfLists; + private List[] arrayOfLists; + private Map map = new HashMap(); + private Map> mapOfLists = new HashMap>(); + public NestedBean() { - + mapOfLists.put("apples", new ArrayList()); } public NestedBean(String foo) { @@ -198,7 +229,23 @@ public class Spr7839Tests { public void setListOfLists(List> listOfLists) { this.listOfLists = listOfLists; } - + + public List[] getArrayOfLists() { + return arrayOfLists; + } + + public void setArrayOfLists(List[] arrayOfLists) { + this.arrayOfLists = arrayOfLists; + } + + public Map> getMapOfLists() { + return mapOfLists; + } + + public void setMapOfLists(Map> mapOfLists) { + this.mapOfLists = mapOfLists; + } + } }