From 66abad25400aab7e6211f75449ec6bde08cae659 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Mon, 12 Jul 2010 20:56:22 +0000 Subject: [PATCH] BeanWrapper preserves annotation information for individual array/list/map elements (SPR-7348) --- .../beans/BeanWrapperImpl.java | 13 +++-- .../FormattingConversionServiceTests.java | 47 ++++++++++++++++--- 2 files changed, 49 insertions(+), 11 deletions(-) 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 93572b3a168..5ea46393b3c 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 @@ -789,7 +789,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); + Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType, + new PropertyTypeDescriptor(pd, new MethodParameter(pd.getReadMethod(), -1), 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); @@ -946,6 +947,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra "in indexed property path '" + propertyName + "': returned null"); } else if (propValue.getClass().isArray()) { + PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName); Class requiredType = propValue.getClass().getComponentType(); int arrayIndex = Integer.parseInt(key); Object oldValue = null; @@ -953,7 +955,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra if (isExtractOldValueForEditor()) { oldValue = Array.get(propValue, arrayIndex); } - Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType); + Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType, + new PropertyTypeDescriptor(pd, new MethodParameter(pd.getReadMethod(), -1), requiredType)); Array.set(propValue, arrayIndex, convertedValue); } catch (IndexOutOfBoundsException ex) { @@ -971,7 +974,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra if (isExtractOldValueForEditor() && index < list.size()) { oldValue = list.get(index); } - Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType); + Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType, + new PropertyTypeDescriptor(pd, new MethodParameter(pd.getReadMethod(), -1), requiredType)); if (index < list.size()) { list.set(index, convertedValue); } @@ -999,7 +1003,8 @@ 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); + Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType, + new PropertyTypeDescriptor(pd, new MethodParameter(pd.getReadMethod(), -1), mapKeyType)); Object oldValue = null; if (isExtractOldValueForEditor()) { oldValue = map.get(convertedMapKey); diff --git a/org.springframework.context/src/test/java/org/springframework/format/support/FormattingConversionServiceTests.java b/org.springframework.context/src/test/java/org/springframework/format/support/FormattingConversionServiceTests.java index 26ca6f3d62c..a37809574cf 100644 --- a/org.springframework.context/src/test/java/org/springframework/format/support/FormattingConversionServiceTests.java +++ b/org.springframework.context/src/test/java/org/springframework/format/support/FormattingConversionServiceTests.java @@ -31,6 +31,9 @@ import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.BeanWrapper; +import org.springframework.beans.PropertyAccessorFactory; import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.i18n.LocaleContextHolder; @@ -99,7 +102,7 @@ public class FormattingConversionServiceTests { PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer(); Properties props = new Properties(); props.setProperty("dateStyle", "S-"); - props.setProperty("datePattern", "M/d/yy"); + props.setProperty("datePattern", "M-d-yy"); ppc.setProperties(props); context.getBeanFactory().registerSingleton("ppc", ppc); context.refresh(); @@ -114,7 +117,7 @@ public class FormattingConversionServiceTests { PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer(); Properties props = new Properties(); props.setProperty("dateStyle", "S-"); - props.setProperty("datePattern", "M/d/yy"); + props.setProperty("datePattern", "M-d-yy"); ppc.setProperties(props); context.registerBeanDefinition("formattingService", new RootBeanDefinition(FormattingConversionServiceFactoryBean.class)); context.getBeanFactory().registerSingleton("ppc", ppc); @@ -148,12 +151,28 @@ public class FormattingConversionServiceTests { dates.add(new LocalDate(2009, 11, 2).toDateTimeAtCurrentTime().toDate()); formatted = (String) formattingService.convert(dates, new TypeDescriptor(modelClass.getField("dates")), TypeDescriptor.valueOf(String.class)); - assertEquals("10/31/09,11/1/09,11/2/09", formatted); - dates = (List) formattingService.convert("10/31/09,11/1/09,11/2/09", + assertEquals("10-31-09,11-1-09,11-2-09", formatted); + dates = (List) formattingService.convert("10-31-09,11-1-09,11-2-09", TypeDescriptor.valueOf(String.class), new TypeDescriptor(modelClass.getField("dates"))); assertEquals(new LocalDate(2009, 10, 31), new LocalDate(dates.get(0))); assertEquals(new LocalDate(2009, 11, 1), new LocalDate(dates.get(1))); assertEquals(new LocalDate(2009, 11, 2), new LocalDate(dates.get(2))); + + Object model = BeanUtils.instantiate(modelClass); + BeanWrapper accessor = PropertyAccessorFactory.forBeanPropertyAccess(model); + accessor.setConversionService(formattingService); + accessor.setPropertyValue("dates", "10-31-09,11-1-09,11-2-09"); + dates = (List) accessor.getPropertyValue("dates"); + assertEquals(new LocalDate(2009, 10, 31), new LocalDate(dates.get(0))); + assertEquals(new LocalDate(2009, 11, 1), new LocalDate(dates.get(1))); + assertEquals(new LocalDate(2009, 11, 2), new LocalDate(dates.get(2))); + accessor.setPropertyValue("dates[0]", "10-30-09"); + accessor.setPropertyValue("dates[1]", "10-1-09"); + accessor.setPropertyValue("dates[2]", "10-2-09"); + dates = (List) accessor.getPropertyValue("dates"); + assertEquals(new LocalDate(2009, 10, 30), new LocalDate(dates.get(0))); + assertEquals(new LocalDate(2009, 10, 1), new LocalDate(dates.get(1))); + assertEquals(new LocalDate(2009, 10, 2), new LocalDate(dates.get(2))); } @Test @@ -190,20 +209,27 @@ public class FormattingConversionServiceTests { } - private static class Model { + public static class Model { @SuppressWarnings("unused") @org.springframework.format.annotation.DateTimeFormat(style="S-") public Date date; @SuppressWarnings("unused") - @org.springframework.format.annotation.DateTimeFormat(pattern="M/d/yy") + @org.springframework.format.annotation.DateTimeFormat(pattern="M-d-yy") public List dates; + public List getDates() { + return dates; + } + + public void setDates(List dates) { + this.dates = dates; + } } - private static class ModelWithPlaceholders { + public static class ModelWithPlaceholders { @SuppressWarnings("unused") @org.springframework.format.annotation.DateTimeFormat(style="${dateStyle}") @@ -213,6 +239,13 @@ public class FormattingConversionServiceTests { @org.springframework.format.annotation.DateTimeFormat(pattern="${datePattern}") public List dates; + public List getDates() { + return dates; + } + + public void setDates(List dates) { + this.dates = dates; + } } }