From 2288b2523eb87e6f1f86eae454af29734f28d7cd Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Thu, 29 Oct 2009 11:18:43 +0000 Subject: [PATCH] SPR-6021 - Allow for using MultiValueMap in GET request for mapping multiple request params --- .../ServletAnnotationControllerTests.java | 56 +++++++++++++++++++ .../support/HandlerMethodInvoker.java | 29 ++++++++++ 2 files changed, 85 insertions(+) diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/ServletAnnotationControllerTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/ServletAnnotationControllerTests.java index 8a4222ae68b..38d878ca03c 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/ServletAnnotationControllerTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/ServletAnnotationControllerTests.java @@ -35,6 +35,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.Iterator; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; @@ -80,6 +81,7 @@ import org.springframework.ui.format.date.DateFormatter; import org.springframework.ui.format.support.GenericFormatterRegistry; import org.springframework.util.SerializationTestUtils; import org.springframework.util.StringUtils; +import org.springframework.util.MultiValueMap; import org.springframework.validation.BindingResult; import org.springframework.validation.Errors; import org.springframework.validation.FieldError; @@ -1146,6 +1148,25 @@ public class ServletAnnotationControllerTests { } + @Test + public void requestParamMap() throws Exception { + initServlet(RequestParamMapController.class); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/map"); + request.addParameter("key1", "value1"); + request.addParameter("key2", new String[]{"value21", "value22"}); + MockHttpServletResponse response = new MockHttpServletResponse(); + + servlet.service(request, response); + assertEquals("key1=value1,key2=value21", response.getContentAsString()); + + request.setRequestURI("/multiValueMap"); + response = new MockHttpServletResponse(); + + servlet.service(request, response); + assertEquals("key1=[value1],key2=[value21,value22]", response.getContentAsString()); + } + /* * Controllers @@ -1942,6 +1963,41 @@ public class ServletAnnotationControllerTests { return new ModelAndView("/something"); } } + + @Controller + public static class RequestParamMapController { + + @RequestMapping("/map") + public void map(@RequestParam Map params, Writer writer) throws IOException { + for (Iterator> it = params.entrySet().iterator(); it.hasNext();) { + Map.Entry entry = it.next(); + writer.write(entry.getKey() + "=" + entry.getValue()); + if (it.hasNext()) { + writer.write(','); + } + + } + } + + @RequestMapping("/multiValueMap") + public void multiValueMap(@RequestParam MultiValueMap params, Writer writer) throws IOException { + for (Iterator>> it1 = params.entrySet().iterator(); it1.hasNext();) { + Map.Entry> entry = it1.next(); + writer.write(entry.getKey() + "=["); + for (Iterator it2 = entry.getValue().iterator(); it2.hasNext();) { + String value = it2.next(); + writer.write(value); + if (it2.hasNext()) { + writer.write(','); + } + } + writer.write(']'); + if (it1.hasNext()) { + writer.write(','); + } + } + } + } } diff --git a/org.springframework.web/src/main/java/org/springframework/web/bind/annotation/support/HandlerMethodInvoker.java b/org.springframework.web/src/main/java/org/springframework/web/bind/annotation/support/HandlerMethodInvoker.java index 5723ddf4f5c..87f4941b507 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/bind/annotation/support/HandlerMethodInvoker.java +++ b/org.springframework.web/src/main/java/org/springframework/web/bind/annotation/support/HandlerMethodInvoker.java @@ -26,6 +26,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.LinkedHashMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -46,6 +47,8 @@ import org.springframework.ui.Model; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; +import org.springframework.util.MultiValueMap; +import org.springframework.util.LinkedMultiValueMap; import org.springframework.validation.BindingResult; import org.springframework.validation.Errors; import org.springframework.web.HttpMediaTypeNotSupportedException; @@ -396,11 +399,15 @@ public class HandlerMethodInvoker { return initBinderArgs; } + @SuppressWarnings("unchecked") private Object resolveRequestParam(String paramName, boolean required, String defaultValue, MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall) throws Exception { Class paramType = methodParam.getParameterType(); + if (Map.class.isAssignableFrom(paramType)) { + return resolveRequestParamMap((Class) paramType, webRequest); + } if (paramName.length() == 0) { paramName = getRequiredParameterName(methodParam); } @@ -428,6 +435,28 @@ public class HandlerMethodInvoker { return binder.convertIfNecessary(paramValue, paramType, methodParam); } + private Map resolveRequestParamMap(Class mapType, NativeWebRequest webRequest) { + Map parameterMap = webRequest.getParameterMap(); + if (MultiValueMap.class.isAssignableFrom(mapType)) { + MultiValueMap result = new LinkedMultiValueMap(parameterMap.size()); + for (Map.Entry entry : parameterMap.entrySet()) { + for (String value : entry.getValue()) { + result.add(entry.getKey(), value); + } + } + return result; + } + else { + Map result = new LinkedHashMap(parameterMap.size()); + for (Map.Entry entry : parameterMap.entrySet()) { + if (entry.getValue().length > 0) { + result.put(entry.getKey(), entry.getValue()[0]); + } + } + return result; + } + } + private Object resolveRequestHeader(String headerName, boolean required, String defaultValue, MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall) throws Exception {