Skip to content

Commit 66abad2

Browse files
committed
BeanWrapper preserves annotation information for individual array/list/map elements (SPR-7348)
1 parent e0e1cb3 commit 66abad2

File tree

2 files changed

+49
-11
lines changed

2 files changed

+49
-11
lines changed

org.springframework.beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -789,7 +789,8 @@ else if (value instanceof Map) {
789789
Class<?> mapKeyType = GenericCollectionTypeResolver.getMapKeyReturnType(pd.getReadMethod(), i + 1);
790790
// IMPORTANT: Do not pass full property name in here - property editors
791791
// must not kick in for map keys but rather only for map values.
792-
Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType);
792+
Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType,
793+
new PropertyTypeDescriptor(pd, new MethodParameter(pd.getReadMethod(), -1), mapKeyType));
793794
// Pass full property name and old value in here, since we want full
794795
// conversion ability for map values.
795796
growMapIfNecessary(map, convertedMapKey, indexedPropertyName, pd, i + 1);
@@ -946,14 +947,16 @@ private void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) thro
946947
"in indexed property path '" + propertyName + "': returned null");
947948
}
948949
else if (propValue.getClass().isArray()) {
950+
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName);
949951
Class requiredType = propValue.getClass().getComponentType();
950952
int arrayIndex = Integer.parseInt(key);
951953
Object oldValue = null;
952954
try {
953955
if (isExtractOldValueForEditor()) {
954956
oldValue = Array.get(propValue, arrayIndex);
955957
}
956-
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType);
958+
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType,
959+
new PropertyTypeDescriptor(pd, new MethodParameter(pd.getReadMethod(), -1), requiredType));
957960
Array.set(propValue, arrayIndex, convertedValue);
958961
}
959962
catch (IndexOutOfBoundsException ex) {
@@ -971,7 +974,8 @@ else if (propValue instanceof List) {
971974
if (isExtractOldValueForEditor() && index < list.size()) {
972975
oldValue = list.get(index);
973976
}
974-
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType);
977+
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType,
978+
new PropertyTypeDescriptor(pd, new MethodParameter(pd.getReadMethod(), -1), requiredType));
975979
if (index < list.size()) {
976980
list.set(index, convertedValue);
977981
}
@@ -999,7 +1003,8 @@ else if (propValue instanceof Map) {
9991003
Map map = (Map) propValue;
10001004
// IMPORTANT: Do not pass full property name in here - property editors
10011005
// must not kick in for map keys but rather only for map values.
1002-
Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType);
1006+
Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType,
1007+
new PropertyTypeDescriptor(pd, new MethodParameter(pd.getReadMethod(), -1), mapKeyType));
10031008
Object oldValue = null;
10041009
if (isExtractOldValueForEditor()) {
10051010
oldValue = map.get(convertedMapKey);

org.springframework.context/src/test/java/org/springframework/format/support/FormattingConversionServiceTests.java

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@
3131
import org.junit.Before;
3232
import org.junit.Test;
3333

34+
import org.springframework.beans.BeanUtils;
35+
import org.springframework.beans.BeanWrapper;
36+
import org.springframework.beans.PropertyAccessorFactory;
3437
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
3538
import org.springframework.beans.factory.support.RootBeanDefinition;
3639
import org.springframework.context.i18n.LocaleContextHolder;
@@ -99,7 +102,7 @@ public void testFormatFieldForAnnotationWithPlaceholders() throws Exception {
99102
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
100103
Properties props = new Properties();
101104
props.setProperty("dateStyle", "S-");
102-
props.setProperty("datePattern", "M/d/yy");
105+
props.setProperty("datePattern", "M-d-yy");
103106
ppc.setProperties(props);
104107
context.getBeanFactory().registerSingleton("ppc", ppc);
105108
context.refresh();
@@ -114,7 +117,7 @@ public void testFormatFieldForAnnotationWithPlaceholdersAndFactoryBean() throws
114117
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
115118
Properties props = new Properties();
116119
props.setProperty("dateStyle", "S-");
117-
props.setProperty("datePattern", "M/d/yy");
120+
props.setProperty("datePattern", "M-d-yy");
118121
ppc.setProperties(props);
119122
context.registerBeanDefinition("formattingService", new RootBeanDefinition(FormattingConversionServiceFactoryBean.class));
120123
context.getBeanFactory().registerSingleton("ppc", ppc);
@@ -148,12 +151,28 @@ public Date convert(DateTime source) {
148151
dates.add(new LocalDate(2009, 11, 2).toDateTimeAtCurrentTime().toDate());
149152
formatted = (String) formattingService.convert(dates,
150153
new TypeDescriptor(modelClass.getField("dates")), TypeDescriptor.valueOf(String.class));
151-
assertEquals("10/31/09,11/1/09,11/2/09", formatted);
152-
dates = (List<Date>) formattingService.convert("10/31/09,11/1/09,11/2/09",
154+
assertEquals("10-31-09,11-1-09,11-2-09", formatted);
155+
dates = (List<Date>) formattingService.convert("10-31-09,11-1-09,11-2-09",
153156
TypeDescriptor.valueOf(String.class), new TypeDescriptor(modelClass.getField("dates")));
154157
assertEquals(new LocalDate(2009, 10, 31), new LocalDate(dates.get(0)));
155158
assertEquals(new LocalDate(2009, 11, 1), new LocalDate(dates.get(1)));
156159
assertEquals(new LocalDate(2009, 11, 2), new LocalDate(dates.get(2)));
160+
161+
Object model = BeanUtils.instantiate(modelClass);
162+
BeanWrapper accessor = PropertyAccessorFactory.forBeanPropertyAccess(model);
163+
accessor.setConversionService(formattingService);
164+
accessor.setPropertyValue("dates", "10-31-09,11-1-09,11-2-09");
165+
dates = (List<Date>) accessor.getPropertyValue("dates");
166+
assertEquals(new LocalDate(2009, 10, 31), new LocalDate(dates.get(0)));
167+
assertEquals(new LocalDate(2009, 11, 1), new LocalDate(dates.get(1)));
168+
assertEquals(new LocalDate(2009, 11, 2), new LocalDate(dates.get(2)));
169+
accessor.setPropertyValue("dates[0]", "10-30-09");
170+
accessor.setPropertyValue("dates[1]", "10-1-09");
171+
accessor.setPropertyValue("dates[2]", "10-2-09");
172+
dates = (List<Date>) accessor.getPropertyValue("dates");
173+
assertEquals(new LocalDate(2009, 10, 30), new LocalDate(dates.get(0)));
174+
assertEquals(new LocalDate(2009, 10, 1), new LocalDate(dates.get(1)));
175+
assertEquals(new LocalDate(2009, 10, 2), new LocalDate(dates.get(2)));
157176
}
158177

159178
@Test
@@ -190,20 +209,27 @@ public void testParseEmptyStringDefault() throws ParseException {
190209
}
191210

192211

193-
private static class Model {
212+
public static class Model {
194213

195214
@SuppressWarnings("unused")
196215
@org.springframework.format.annotation.DateTimeFormat(style="S-")
197216
public Date date;
198217

199218
@SuppressWarnings("unused")
200-
@org.springframework.format.annotation.DateTimeFormat(pattern="M/d/yy")
219+
@org.springframework.format.annotation.DateTimeFormat(pattern="M-d-yy")
201220
public List<Date> dates;
202221

222+
public List<Date> getDates() {
223+
return dates;
224+
}
225+
226+
public void setDates(List<Date> dates) {
227+
this.dates = dates;
228+
}
203229
}
204230

205231

206-
private static class ModelWithPlaceholders {
232+
public static class ModelWithPlaceholders {
207233

208234
@SuppressWarnings("unused")
209235
@org.springframework.format.annotation.DateTimeFormat(style="${dateStyle}")
@@ -213,6 +239,13 @@ private static class ModelWithPlaceholders {
213239
@org.springframework.format.annotation.DateTimeFormat(pattern="${datePattern}")
214240
public List<Date> dates;
215241

242+
public List<Date> getDates() {
243+
return dates;
244+
}
245+
246+
public void setDates(List<Date> dates) {
247+
this.dates = dates;
248+
}
216249
}
217250

218251
}

0 commit comments

Comments
 (0)