BeanWrapper preserves annotation information for individual array/list/map elements (SPR-7348)

This commit is contained in:
Juergen Hoeller 2010-07-12 20:56:22 +00:00
parent e0e1cb3c24
commit 66abad2540
2 changed files with 49 additions and 11 deletions

View File

@ -789,7 +789,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
Class<?> mapKeyType = GenericCollectionTypeResolver.getMapKeyReturnType(pd.getReadMethod(), i + 1); Class<?> mapKeyType = GenericCollectionTypeResolver.getMapKeyReturnType(pd.getReadMethod(), i + 1);
// IMPORTANT: Do not pass full property name in here - property editors // IMPORTANT: Do not pass full property name in here - property editors
// must not kick in for map keys but rather only for map values. // 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 // Pass full property name and old value in here, since we want full
// conversion ability for map values. // conversion ability for map values.
growMapIfNecessary(map, convertedMapKey, indexedPropertyName, pd, i + 1); 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"); "in indexed property path '" + propertyName + "': returned null");
} }
else if (propValue.getClass().isArray()) { else if (propValue.getClass().isArray()) {
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName);
Class requiredType = propValue.getClass().getComponentType(); Class requiredType = propValue.getClass().getComponentType();
int arrayIndex = Integer.parseInt(key); int arrayIndex = Integer.parseInt(key);
Object oldValue = null; Object oldValue = null;
@ -953,7 +955,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
if (isExtractOldValueForEditor()) { if (isExtractOldValueForEditor()) {
oldValue = Array.get(propValue, arrayIndex); 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); Array.set(propValue, arrayIndex, convertedValue);
} }
catch (IndexOutOfBoundsException ex) { catch (IndexOutOfBoundsException ex) {
@ -971,7 +974,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
if (isExtractOldValueForEditor() && index < list.size()) { if (isExtractOldValueForEditor() && index < list.size()) {
oldValue = list.get(index); 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()) { if (index < list.size()) {
list.set(index, convertedValue); list.set(index, convertedValue);
} }
@ -999,7 +1003,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
Map map = (Map) propValue; Map map = (Map) propValue;
// IMPORTANT: Do not pass full property name in here - property editors // IMPORTANT: Do not pass full property name in here - property editors
// must not kick in for map keys but rather only for map values. // 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; Object oldValue = null;
if (isExtractOldValueForEditor()) { if (isExtractOldValueForEditor()) {
oldValue = map.get(convertedMapKey); oldValue = map.get(convertedMapKey);

View File

@ -31,6 +31,9 @@ import static org.junit.Assert.*;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; 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.config.PropertyPlaceholderConfigurer;
import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.context.i18n.LocaleContextHolder;
@ -99,7 +102,7 @@ public class FormattingConversionServiceTests {
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer(); PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
Properties props = new Properties(); Properties props = new Properties();
props.setProperty("dateStyle", "S-"); props.setProperty("dateStyle", "S-");
props.setProperty("datePattern", "M/d/yy"); props.setProperty("datePattern", "M-d-yy");
ppc.setProperties(props); ppc.setProperties(props);
context.getBeanFactory().registerSingleton("ppc", ppc); context.getBeanFactory().registerSingleton("ppc", ppc);
context.refresh(); context.refresh();
@ -114,7 +117,7 @@ public class FormattingConversionServiceTests {
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer(); PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
Properties props = new Properties(); Properties props = new Properties();
props.setProperty("dateStyle", "S-"); props.setProperty("dateStyle", "S-");
props.setProperty("datePattern", "M/d/yy"); props.setProperty("datePattern", "M-d-yy");
ppc.setProperties(props); ppc.setProperties(props);
context.registerBeanDefinition("formattingService", new RootBeanDefinition(FormattingConversionServiceFactoryBean.class)); context.registerBeanDefinition("formattingService", new RootBeanDefinition(FormattingConversionServiceFactoryBean.class));
context.getBeanFactory().registerSingleton("ppc", ppc); context.getBeanFactory().registerSingleton("ppc", ppc);
@ -148,12 +151,28 @@ public class FormattingConversionServiceTests {
dates.add(new LocalDate(2009, 11, 2).toDateTimeAtCurrentTime().toDate()); dates.add(new LocalDate(2009, 11, 2).toDateTimeAtCurrentTime().toDate());
formatted = (String) formattingService.convert(dates, formatted = (String) formattingService.convert(dates,
new TypeDescriptor(modelClass.getField("dates")), TypeDescriptor.valueOf(String.class)); new TypeDescriptor(modelClass.getField("dates")), TypeDescriptor.valueOf(String.class));
assertEquals("10/31/09,11/1/09,11/2/09", formatted); assertEquals("10-31-09,11-1-09,11-2-09", formatted);
dates = (List<Date>) formattingService.convert("10/31/09,11/1/09,11/2/09", dates = (List<Date>) formattingService.convert("10-31-09,11-1-09,11-2-09",
TypeDescriptor.valueOf(String.class), new TypeDescriptor(modelClass.getField("dates"))); TypeDescriptor.valueOf(String.class), new TypeDescriptor(modelClass.getField("dates")));
assertEquals(new LocalDate(2009, 10, 31), new LocalDate(dates.get(0))); 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, 1), new LocalDate(dates.get(1)));
assertEquals(new LocalDate(2009, 11, 2), new LocalDate(dates.get(2))); 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<Date>) 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<Date>) 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 @Test
@ -190,20 +209,27 @@ public class FormattingConversionServiceTests {
} }
private static class Model { public static class Model {
@SuppressWarnings("unused") @SuppressWarnings("unused")
@org.springframework.format.annotation.DateTimeFormat(style="S-") @org.springframework.format.annotation.DateTimeFormat(style="S-")
public Date date; public Date date;
@SuppressWarnings("unused") @SuppressWarnings("unused")
@org.springframework.format.annotation.DateTimeFormat(pattern="M/d/yy") @org.springframework.format.annotation.DateTimeFormat(pattern="M-d-yy")
public List<Date> dates; public List<Date> dates;
public List<Date> getDates() {
return dates;
}
public void setDates(List<Date> dates) {
this.dates = dates;
}
} }
private static class ModelWithPlaceholders { public static class ModelWithPlaceholders {
@SuppressWarnings("unused") @SuppressWarnings("unused")
@org.springframework.format.annotation.DateTimeFormat(style="${dateStyle}") @org.springframework.format.annotation.DateTimeFormat(style="${dateStyle}")
@ -213,6 +239,13 @@ public class FormattingConversionServiceTests {
@org.springframework.format.annotation.DateTimeFormat(pattern="${datePattern}") @org.springframework.format.annotation.DateTimeFormat(pattern="${datePattern}")
public List<Date> dates; public List<Date> dates;
public List<Date> getDates() {
return dates;
}
public void setDates(List<Date> dates) {
this.dates = dates;
}
} }
} }