diff --git a/spring-web/src/main/java/org/springframework/web/bind/WebDataBinder.java b/spring-web/src/main/java/org/springframework/web/bind/WebDataBinder.java index 7756239826..442b97185b 100644 --- a/spring-web/src/main/java/org/springframework/web/bind/WebDataBinder.java +++ b/spring-web/src/main/java/org/springframework/web/bind/WebDataBinder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2016 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. @@ -17,11 +17,13 @@ package org.springframework.web.bind; import java.lang.reflect.Array; +import java.util.Collection; import java.util.List; import java.util.Map; import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.PropertyValue; +import org.springframework.core.CollectionFactory; import org.springframework.validation.DataBinder; import org.springframework.web.multipart.MultipartFile; @@ -40,6 +42,7 @@ import org.springframework.web.multipart.MultipartFile; * * @author Juergen Hoeller * @author Scott Andrews + * @author Brian Clozel * @since 1.2 * @see #registerCustomEditor * @see #setAllowedFields @@ -243,26 +246,41 @@ public class WebDataBinder extends DataBinder { /** * Determine an empty value for the specified field. - *

Default implementation returns {@code Boolean.FALSE} - * for boolean fields and an empty array of array types. - * Else, {@code null} is used as default. + *

Default implementation returns: + *

* @param field the name of the field * @param fieldType the type of the field * @return the empty value (for most fields: null) */ protected Object getEmptyValue(String field, Class fieldType) { - if (fieldType != null && boolean.class == fieldType || Boolean.class == fieldType) { - // Special handling of boolean property. - return Boolean.FALSE; - } - else if (fieldType != null && fieldType.isArray()) { - // Special handling of array property. - return Array.newInstance(fieldType.getComponentType(), 0); - } - else { - // Default value: try null. - return null; + if (fieldType != null) { + try { + if (boolean.class == fieldType || Boolean.class == fieldType) { + // Special handling of boolean property. + return Boolean.FALSE; + } + else if (fieldType.isArray()) { + // Special handling of array property. + return Array.newInstance(fieldType.getComponentType(), 0); + } + else if (Collection.class.isAssignableFrom(fieldType)) { + return CollectionFactory.createCollection(fieldType, 0); + } + else if (Map.class.isAssignableFrom(fieldType)) { + return CollectionFactory.createMap(fieldType, 0); + } + } catch (IllegalArgumentException exc) { + return null; + } } + // Default value: try null. + return null; } /** diff --git a/spring-web/src/test/java/org/springframework/web/bind/support/WebRequestDataBinderTests.java b/spring-web/src/test/java/org/springframework/web/bind/support/WebRequestDataBinderTests.java index 32b4c0e114..508be6d3ab 100644 --- a/spring-web/src/test/java/org/springframework/web/bind/support/WebRequestDataBinderTests.java +++ b/spring-web/src/test/java/org/springframework/web/bind/support/WebRequestDataBinderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -16,10 +16,15 @@ package org.springframework.web.bind.support; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + import java.beans.PropertyEditorSupport; import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.Set; import org.junit.Test; @@ -34,8 +39,6 @@ import org.springframework.web.bind.ServletRequestParameterPropertyValues; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.multipart.support.StringMultipartFileEditor; -import static org.junit.Assert.*; - /** * @author Juergen Hoeller */ @@ -126,6 +129,31 @@ public class WebRequestDataBinderTests { assertFalse(target.isPostProcessed()); } + // SPR-13502 + @Test + public void testCollectionFieldsDefault() throws Exception { + TestBean target = new TestBean(); + target.setSomeSet(null); + target.setSomeList(null); + target.setSomeMap(null); + WebRequestDataBinder binder = new WebRequestDataBinder(target); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("_someSet", "visible"); + request.addParameter("_someList", "visible"); + request.addParameter("_someMap", "visible"); + + binder.bind(new ServletWebRequest(request)); + assertThat(target.getSomeSet(), notNullValue()); + assertThat(target.getSomeSet(), isA(Set.class)); + + assertThat(target.getSomeList(), notNullValue()); + assertThat(target.getSomeList(), isA(List.class)); + + assertThat(target.getSomeMap(), notNullValue()); + assertThat(target.getSomeMap(), isA(Map.class)); + } + @Test public void testFieldDefaultPreemptsFieldMarker() throws Exception { TestBean target = new TestBean();