diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMapping.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMapping.java index b2a182a67da..5e6452c3cb7 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMapping.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMapping.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2013 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. @@ -26,14 +26,18 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import org.springframework.http.MediaType; +import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import org.springframework.web.HttpMediaTypeNotAcceptableException; import org.springframework.web.HttpMediaTypeNotSupportedException; import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.UnsatisfiedServletRequestParameterException; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping; +import org.springframework.web.servlet.mvc.condition.NameValueExpression; +import org.springframework.web.servlet.mvc.condition.ParamsRequestCondition; /** * Abstract base class for classes for which {@link RequestMappingInfo} defines @@ -141,14 +145,17 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe Set consumableMediaTypes; Set producibleMediaTypes; + Set paramConditions; if (patternAndMethodMatches.isEmpty()) { consumableMediaTypes = getConsumableMediaTypes(request, patternMatches); producibleMediaTypes = getProdicubleMediaTypes(request, patternMatches); + paramConditions = getRequestParams(request, patternMatches); } else { consumableMediaTypes = getConsumableMediaTypes(request, patternAndMethodMatches); producibleMediaTypes = getProdicubleMediaTypes(request, patternAndMethodMatches); + paramConditions = getRequestParams(request, patternAndMethodMatches); } if (!consumableMediaTypes.isEmpty()) { @@ -161,6 +168,10 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe else if (!producibleMediaTypes.isEmpty()) { throw new HttpMediaTypeNotAcceptableException(new ArrayList(producibleMediaTypes)); } + else if (!CollectionUtils.isEmpty(paramConditions)) { + String[] params = paramConditions.toArray(new String[paramConditions.size()]); + throw new UnsatisfiedServletRequestParameterException(params, request.getParameterMap()); + } else { return null; } @@ -186,4 +197,18 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe return result; } + private Set getRequestParams(HttpServletRequest request, Set partialMatches) { + for (RequestMappingInfo partialMatch : partialMatches) { + ParamsRequestCondition condition = partialMatch.getParamsCondition(); + if (!CollectionUtils.isEmpty(condition.getExpressions()) && (condition.getMatchingCondition(request) == null)) { + Set expressions = new HashSet(); + for (NameValueExpression expr : condition.getExpressions()) { + expressions.add(expr.toString()); + } + return expressions; + } + } + return null; + } + } diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMappingTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMappingTests.java index 1fe3a892aa7..b85a25d4a06 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMappingTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMappingTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2013 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. @@ -39,6 +39,7 @@ import org.springframework.stereotype.Controller; import org.springframework.web.HttpMediaTypeNotAcceptableException; import org.springframework.web.HttpMediaTypeNotSupportedException; import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.UnsatisfiedServletRequestParameterException; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @@ -195,6 +196,19 @@ public class RequestMappingInfoHandlerMappingTests { } } + @Test + public void testUnsatisfiedServletRequestParameterException() throws Exception { + try { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/params"); + this.mapping.getHandler(request); + fail("UnsatisfiedServletRequestParameterException expected"); + } + catch (UnsatisfiedServletRequestParameterException ex) { + assertArrayEquals("Invalid request parameter conditions", + new String[] { "foo=bar" }, ex.getParamConditions()); + } + } + @Test public void uriTemplateVariables() { PatternsRequestCondition patterns = new PatternsRequestCondition("/{path1}/{path2}"); @@ -300,6 +314,11 @@ public class RequestMappingInfoHandlerMappingTests { return ""; } + @RequestMapping(value = "/params", params="foo=bar") + public String param() { + return ""; + } + @RequestMapping(value = "/content", produces="application/xml") public String xmlContent() { return "";