From 90f17a9e675eced0bf235703f9097ecaac4ee1a7 Mon Sep 17 00:00:00 2001 From: kssumin <201566@jnu.ac.kr> Date: Thu, 3 Apr 2025 19:35:22 +0900 Subject: [PATCH] Fix inconsistent query parameter conversion for String params Signed-off-by: kssumin <201566@jnu.ac.kr> --- .../bind/support/WebRequestDataBinder.java | 44 +++++++++++++++++++ .../support/WebRequestDataBinderTests.java | 13 ++++++ 2 files changed, 57 insertions(+) diff --git a/spring-web/src/main/java/org/springframework/web/bind/support/WebRequestDataBinder.java b/spring-web/src/main/java/org/springframework/web/bind/support/WebRequestDataBinder.java index 1e393922f304..eab6e684d5f1 100644 --- a/spring-web/src/main/java/org/springframework/web/bind/support/WebRequestDataBinder.java +++ b/spring-web/src/main/java/org/springframework/web/bind/support/WebRequestDataBinder.java @@ -21,7 +21,10 @@ import jakarta.servlet.http.Part; import org.jspecify.annotations.Nullable; +import org.springframework.beans.ConfigurablePropertyAccessor; +import org.springframework.beans.InvalidPropertyException; import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.PropertyValue; import org.springframework.core.MethodParameter; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; @@ -73,6 +76,7 @@ * * @author Juergen Hoeller * @author Brian Clozel + * @author Sumin Kim * @since 2.5.2 * @see #bind(org.springframework.web.context.request.WebRequest) * @see #registerCustomEditor @@ -167,6 +171,46 @@ else if (StringUtils.startsWithIgnoreCase( doBind(mpvs); } + /** + * Binds the given property values to this binder's target. + * <p>This implementation handles the case where string array values need to be + * converted to single string values if the property is not array-typed. + * <p>For properties that don't have the "[]" suffix but contain string array values, + * this method will use only the first array element when the target property + * is not of array type. + * + * @param mpvs the property values to bind + * @see #getTarget() + * @see #getPropertyAccessor() + */ + @Override + protected void doBind(MutablePropertyValues mpvs) { + Object target = getTarget(); + if (target == null) { + super.doBind(mpvs); + return; + } + + ConfigurablePropertyAccessor accessor = getPropertyAccessor(); + + for (PropertyValue pv : mpvs.getPropertyValues()) { + String propertyName = pv.getName(); + Object value = pv.getValue(); + if (!propertyName.endsWith("[]") && value instanceof String[] array && array.length > 0) { + try { + Class<?> propertyType = accessor.getPropertyType(propertyName); + if (propertyType == null || !propertyType.isArray()) { + mpvs.add(propertyName, new String[] { array[0] }); + } + } + catch (InvalidPropertyException ex) { + mpvs.add(propertyName, new String[] { array[0] }); + } + } + } + super.doBind(mpvs); + } + /** * Treats errors as fatal. * <p>Use this method only if it's an error if the input isn't valid. 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 cc89017f3624..8e1fdd961bfd 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 @@ -40,6 +40,7 @@ /** * @author Juergen Hoeller + * @author Sumin Kim */ class WebRequestDataBinderTests { @@ -124,6 +125,18 @@ public void testFieldWithEmptyArrayIndex() { assertThat(target.getStringArray()).containsExactly("ONE", "TWO"); } + @Test + public void testSameNameParameterFirstValueConversion() { + TestBean target = new TestBean(); + WebRequestDataBinder binder = new WebRequestDataBinder(target); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("touchy", "ONE"); + request.addParameter("touchy", "TWO"); + binder.bind(new ServletWebRequest(request)); + assertThat(target.getTouchy()).isEqualTo("ONE"); + } + @Test void testFieldDefault() { TestBean target = new TestBean();