From 355d394d7fff72844445839a7d8d2b359aec0ced Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Sat, 8 May 2021 19:37:21 +0200 Subject: [PATCH] Polish contribution See gh-25200 --- .../annotation/ModelAttributeMethodProcessor.java | 14 +++++++++----- .../ModelAttributeMethodProcessorTests.java | 9 ++++----- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessor.java b/spring-web/src/main/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessor.java index 4fc49690d27..cd63b46290d 100644 --- a/spring-web/src/main/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessor.java +++ b/spring-web/src/main/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessor.java @@ -40,6 +40,7 @@ import org.springframework.beans.TypeMismatchException; import org.springframework.core.MethodParameter; import org.springframework.lang.Nullable; import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import org.springframework.validation.BindException; import org.springframework.validation.BindingResult; @@ -257,6 +258,14 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol String paramName = paramNames[i]; Class paramType = paramTypes[i]; Object value = webRequest.getParameterValues(paramName); + + // Since WebRequest#getParameter exposes a single-value parameter as an array + // with a single element, we unwrap the single value in such cases, analogous + // to WebExchangeDataBinder.addBindValue(Map, String, List). + if (ObjectUtils.isArray(value) && Array.getLength(value) == 1) { + value = Array.get(value, 0); + } + if (value == null) { if (fieldDefaultPrefix != null) { value = webRequest.getParameter(fieldDefaultPrefix + paramName); @@ -271,11 +280,6 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol } } - // Singular web parameters are wrapped with array, extract it so it can be picked up by conversion service later on - if (value != null && value.getClass().isArray() && Array.getLength(value) == 1) { - value = Array.get(value, 0); - } - try { MethodParameter methodParam = new FieldAwareConstructorParameter(ctor, i, paramName); if (value == null && methodParam.isOptional()) { diff --git a/spring-web/src/test/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessorTests.java b/spring-web/src/test/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessorTests.java index 33f5acfd2ba..bc3be0e7aa9 100644 --- a/spring-web/src/test/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessorTests.java +++ b/spring-web/src/test/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessorTests.java @@ -19,7 +19,6 @@ package org.springframework.web.method.annotation; import java.lang.annotation.Retention; import java.lang.annotation.Target; import java.lang.reflect.Method; -import java.util.Arrays; import java.util.List; import org.junit.jupiter.api.BeforeEach; @@ -271,7 +270,7 @@ public class ModelAttributeMethodProcessorTests { } @Test // gh-25182 - public void testResolveConstructorListParameter() throws Exception { + public void resolveConstructorListArgumentFromCommaSeparatedRequestParameter() throws Exception { MockHttpServletRequest mockRequest = new MockHttpServletRequest(); mockRequest.addParameter("listOfStrings", "1,2"); ServletWebRequest requestWithParam = new ServletWebRequest(mockRequest); @@ -281,14 +280,14 @@ public class ModelAttributeMethodProcessorTests { .willAnswer(invocation -> { WebRequestDataBinder binder = new WebRequestDataBinder(invocation.getArgument(1)); - // Add conversion service which will convert "1,2" to List of size 2 + // Add conversion service which will convert "1,2" to a list binder.setConversionService(new DefaultFormattingConversionService()); return binder; }); Object resolved = this.processor.resolveArgument(this.beanWithConstructorArgs, this.container, requestWithParam, factory); - assertThat(resolved).isNotNull(); - assertThat(((TestBeanWithConstructorArgs) resolved).listOfStrings).isEqualTo(Arrays.asList("1", "2")); + assertThat(resolved).isInstanceOf(TestBeanWithConstructorArgs.class); + assertThat(((TestBeanWithConstructorArgs) resolved).listOfStrings).containsExactly("1", "2"); } private void testGetAttributeFromModel(String expectedAttrName, MethodParameter param) throws Exception {