From ed9d9a402ba8ffa2cacebea35f6192bdc898ce4d Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Thu, 21 Apr 2011 15:18:45 +0000 Subject: [PATCH] SPR-7543 Add @PathVariables to the model --- .../PathVariableMethodArgumentResolver.java | 12 ++++++++ ...gHandlerMethodAdapterIntegrationTests.java | 2 +- ...thVariableMethodArgumentResolverTests.java | 13 +++++--- ...tractNamedValueMethodArgumentResolver.java | 30 +++++++++++++++---- 4 files changed, 46 insertions(+), 11 deletions(-) diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/PathVariableMethodArgumentResolver.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/PathVariableMethodArgumentResolver.java index 00799c6e63..2919bc14d9 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/PathVariableMethodArgumentResolver.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/PathVariableMethodArgumentResolver.java @@ -27,6 +27,7 @@ import org.springframework.web.bind.annotation.ValueConstants; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.method.annotation.support.AbstractNamedValueMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; import org.springframework.web.servlet.HandlerMapping; /** @@ -73,6 +74,17 @@ public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethod throw new IllegalStateException("Could not find the URL template variable [" + name + "]"); } + @Override + protected void handleResolvedValue(Object arg, + String name, + MethodParameter parameter, + ModelAndViewContainer mavContainer, + NativeWebRequest webRequest) { + if (mavContainer != null) { + mavContainer.addAttribute(name, arg); + } + } + private static class PathVariableNamedValueInfo extends NamedValueInfo { private PathVariableNamedValueInfo(PathVariable annotation) { diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodAdapterIntegrationTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodAdapterIntegrationTests.java index 524ed59be2..b4019459af 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodAdapterIntegrationTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodAdapterIntegrationTests.java @@ -293,7 +293,7 @@ public class RequestMappingHandlerMethodAdapterIntegrationTests { @ModelAttribute OtherUser otherUser, Model model) throws Exception { - model.addAttribute("cookie", cookie).addAttribute("pathvar", pathvar).addAttribute("header", header) + model.addAttribute("cookie", cookie).addAttribute("header", header) .addAttribute("systemHeader", systemHeader).addAttribute("headerMap", headerMap) .addAttribute("dateParam", dateParam).addAttribute("paramMap", paramMap) .addAttribute("paramByConvention", paramByConvention).addAttribute("value", value) diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/PathVariableMethodArgumentResolverTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/PathVariableMethodArgumentResolverTests.java index f5679e160a..22ddfd9c7a 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/PathVariableMethodArgumentResolverTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/PathVariableMethodArgumentResolverTests.java @@ -32,6 +32,7 @@ import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.context.request.ServletWebRequest; +import org.springframework.web.method.support.ModelAndViewContainer; import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.mvc.method.annotation.support.PathVariableMethodArgumentResolver; @@ -48,6 +49,8 @@ public class PathVariableMethodArgumentResolverTests { private MethodParameter paramString; + private ModelAndViewContainer mavContainer; + private ServletWebRequest webRequest; private MockHttpServletRequest request; @@ -60,6 +63,7 @@ public class PathVariableMethodArgumentResolverTests { paramNamedString = new MethodParameter(method, 0); paramString = new MethodParameter(method, 1); + mavContainer = new ModelAndViewContainer(); request = new MockHttpServletRequest(); webRequest = new ServletWebRequest(request, new MockHttpServletResponse()); } @@ -76,13 +80,14 @@ public class PathVariableMethodArgumentResolverTests { uriTemplateVars.put("name", "value"); request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriTemplateVars); - String result = (String) resolver.resolveArgument(paramNamedString, null, webRequest, null); - assertEquals("value", result); + String result = (String) resolver.resolveArgument(paramNamedString, mavContainer, webRequest, null); + assertEquals("PathVariable not resolved correctly", "value", result); + assertEquals("PathVariable not added to the model", "value", mavContainer.getAttribute("name")); } - + @Test(expected = IllegalStateException.class) public void handleMissingValue() throws Exception { - resolver.resolveArgument(paramNamedString, null, webRequest, null); + resolver.resolveArgument(paramNamedString, mavContainer, webRequest, null); fail("Unresolved path variable should lead to exception."); } diff --git a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/AbstractNamedValueMethodArgumentResolver.java b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/AbstractNamedValueMethodArgumentResolver.java index 584829d0da..a2ca492ef2 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/AbstractNamedValueMethodArgumentResolver.java +++ b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/AbstractNamedValueMethodArgumentResolver.java @@ -42,6 +42,7 @@ import org.springframework.web.method.support.ModelAndViewContainer; *
  • Obtain named value information for a method parameter *
  • Resolve names into argument values *
  • Handle missing argument values when argument values are required + *
  • Optionally handle a resolved value * *

    A default value string can contain ${...} placeholders and Spring Expression Language #{...} expressions. * For this to work a {@link ConfigurableBeanFactory} must be supplied to the class constructor. @@ -87,16 +88,17 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle else if (namedValueInfo.required) { handleMissingValue(namedValueInfo.name, parameter); } - arg = checkForNull(namedValueInfo.name, arg, paramType); + arg = handleNullValue(namedValueInfo.name, arg, paramType); } if (binderFactory != null) { WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name); - return binder.convertIfNecessary(arg, paramType, parameter); - } - else { - return arg; + arg = binder.convertIfNecessary(arg, paramType, parameter); } + + handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest); + + return arg; } /** @@ -170,7 +172,10 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle */ protected abstract void handleMissingValue(String name, MethodParameter parameter) throws ServletException; - private Object checkForNull(String name, Object value, Class paramType) { + /** + * A {@code null} results in a {@code false} value for {@code boolean}s or an exception for other primitives. + */ + private Object handleNullValue(String name, Object value, Class paramType) { if (value == null) { if (Boolean.TYPE.equals(paramType)) { return Boolean.FALSE; @@ -184,6 +189,19 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle return value; } + /** + * Invoked after a value is resolved. + * @param arg the resolved argument value + * @param name the argument name + * @param parameter the argument parameter type + * @param mavContainer the {@link ModelAndViewContainer}, which may be {@code null} + * @param webRequest the current request + */ + protected void handleResolvedValue(Object arg, String name, MethodParameter parameter, + ModelAndViewContainer mavContainer, NativeWebRequest webRequest) { + + } + /** * Represents the information about a named value, including name, whether it's required and a default value. */