From aa065e83100ace913de9f46ff38aeb84a4d85229 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Wed, 13 Apr 2011 23:15:19 +0000 Subject: [PATCH] SPR-8214 Javadoc and polish --- ...bstractHandlerMethodExceptionResolver.java | 2 +- .../method/AbstractHandlerMethodAdapter.java | 5 +- .../RequestMappingHandlerMethodAdapter.java | 4 +- ...vletInitBinderMethodDataBinderFactory.java | 2 +- .../ServletInvocableHandlerMethod.java | 42 ++++--- ...stractMessageConverterMethodProcessor.java | 6 +- .../DefaultMethodReturnValueHandler.java | 25 ++-- .../support/HttpEntityMethodProcessor.java | 29 ++--- .../ModelAndViewMethodReturnValueHandler.java | 10 +- .../PathVariableMethodArgumentResolver.java | 33 ++--- .../RequestResponseBodyMethodProcessor.java | 11 +- ...vletCookieValueMethodArgumentResolver.java | 22 ++-- .../ServletModelAttributeMethodProcessor.java | 15 +-- .../ServletRequestMethodArgumentResolver.java | 69 ++++++----- ...ServletResponseMethodArgumentResolver.java | 34 +++-- .../ServletWebArgumentResolverAdapter.java | 10 +- .../support/ViewMethodReturnValueHandler.java | 10 +- .../HttpEntityMethodProcessorTests.java | 13 +- ...thVariableMethodArgumentResolverTests.java | 7 +- ...questResponseBodyMethodProcessorTests.java | 15 +-- ...ookieValueMethodArgumentResolverTests.java | 9 +- ...letRequestMethodArgumentResolverTests.java | 25 ++-- ...etResponseMethodArgumentResolverTests.java | 5 - ...actCookieValueMethodArgumentResolver.java} | 50 ++++---- ...tractNamedValueMethodArgumentResolver.java | 117 ++++++++++-------- ...> AbstractWebArgumentResolverAdapter.java} | 45 ++++--- .../support/ErrorsMethodArgumentResolver.java | 16 +-- ...ExpressionValueMethodArgumentResolver.java | 28 +++-- .../ModelAttributeMethodProcessor.java | 44 ++++--- .../support/ModelMethodProcessor.java | 14 +-- ...equestHeaderMapMethodArgumentResolver.java | 17 +-- .../RequestHeaderMethodArgumentResolver.java | 31 +++-- ...RequestParamMapMethodArgumentResolver.java | 18 +-- .../RequestParamMethodArgumentResolver.java | 53 ++++---- .../support/ModelMethodProcessorTests.java | 6 - ...tHeaderMapMethodArgumentResolverTests.java | 6 - ...uestHeaderMethodArgumentResolverTests.java | 6 - ...stParamMapMethodArgumentResolverTests.java | 6 - ...questParamMethodArgumentResolverTests.java | 8 -- .../WebArgumentResolverAdapterTests.java | 18 ++- 40 files changed, 466 insertions(+), 420 deletions(-) rename org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/{CookieValueMethodArgumentResolver.java => AbstractCookieValueMethodArgumentResolver.java} (55%) rename org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/{WebArgumentResolverAdapter.java => AbstractWebArgumentResolverAdapter.java} (59%) diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodExceptionResolver.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodExceptionResolver.java index a561a6992da..edf5a770f19 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodExceptionResolver.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodExceptionResolver.java @@ -24,7 +24,7 @@ import org.springframework.web.servlet.ModelAndView; /** * Abstract base class for {@link org.springframework.web.servlet.HandlerExceptionResolver HandlerExceptionResolver} - * implementations that support {@link HandlerMethod HandlerMethod}s. + * implementations that support handling exceptions from {@link HandlerMethod}s rather than handlers. * * @author Rossen Stoyanchev * @since 3.1 diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/AbstractHandlerMethodAdapter.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/AbstractHandlerMethodAdapter.java index f4f64d01e9a..3246388be4a 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/AbstractHandlerMethodAdapter.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/AbstractHandlerMethodAdapter.java @@ -26,10 +26,11 @@ import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.support.WebContentGenerator; /** - * Abstract base class for {@link HandlerAdapter} implementations that support {@link HandlerMethod}s. - * Contains template methods for handling these handler method. + * Abstract base class for {@link HandlerAdapter} implementations that support the handling of requests through + * the execution of {@link HandlerMethod}s rather than handlers. * * @author Arjen Poutsma + * @since 3.1 */ public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered { diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodAdapter.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodAdapter.java index 230bfec9f2e..363d0a5e4e8 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodAdapter.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodAdapter.java @@ -374,7 +374,7 @@ public class RequestMappingHandlerMethodAdapter extends AbstractHandlerMethodAda resolvers.add(new RequestParamMethodArgumentResolver(beanFactory, false)); resolvers.add(new RequestParamMapMethodArgumentResolver()); - resolvers.add(new PathVariableMethodArgumentResolver(beanFactory)); + resolvers.add(new PathVariableMethodArgumentResolver()); resolvers.add(new ServletModelAttributeMethodProcessor(false)); resolvers.add(new RequestResponseBodyMethodProcessor(messageConverters)); resolvers.add(new RequestHeaderMethodArgumentResolver(beanFactory)); @@ -404,7 +404,7 @@ public class RequestMappingHandlerMethodAdapter extends AbstractHandlerMethodAda // Annotation-based resolvers resolvers.add(new RequestParamMethodArgumentResolver(beanFactory, false)); resolvers.add(new RequestParamMapMethodArgumentResolver()); - resolvers.add(new PathVariableMethodArgumentResolver(beanFactory)); + resolvers.add(new PathVariableMethodArgumentResolver()); resolvers.add(new ExpressionValueMethodArgumentResolver(beanFactory)); // Type-based resolvers diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletInitBinderMethodDataBinderFactory.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletInitBinderMethodDataBinderFactory.java index 8dcc54515c8..8f96204952b 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletInitBinderMethodDataBinderFactory.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletInitBinderMethodDataBinderFactory.java @@ -25,7 +25,7 @@ import org.springframework.web.method.annotation.InitBinderMethodDataBinderFacto import org.springframework.web.method.support.InvocableHandlerMethod; /** - * An {@link InitBinderMethodDataBinderFactory} for Servlet environments. + * An {@link InitBinderMethodDataBinderFactory} that creates a {@link ServletRequestDataBinder}. * * @author Rossen Stoyanchev * @since 3.1 diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletInvocableHandlerMethod.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletInvocableHandlerMethod.java index d7b204a8b46..fc920b9c4cb 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletInvocableHandlerMethod.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletInvocableHandlerMethod.java @@ -30,16 +30,19 @@ import org.springframework.web.method.support.HandlerMethodReturnValueHandlerCom import org.springframework.web.method.support.InvocableHandlerMethod; import org.springframework.web.method.support.ModelAndViewContainer; import org.springframework.web.servlet.View; +import org.springframework.web.servlet.mvc.method.annotation.support.ServletResponseMethodArgumentResolver; /** - * Extends {@link InvocableHandlerMethod} with the ability to handle the return value through registered - * {@link HandlerMethodArgumentResolver}s. + * Extends {@link InvocableHandlerMethod} with the ability to handle the value returned from the method through + * a registered {@link HandlerMethodArgumentResolver} that supports the given return value type. + * Return value handling may include writing to the response or updating the {@link ModelAndViewContainer} structure. * - *

The {@link ModelAndViewContainer} for the request contains the results from the handling of the return value. - * It can be used to access model attributes and view selection and to check if view resolution is needed. + *

If the underlying method has a {@link ResponseStatus} instruction, the status on the response is set + * accordingly after the method is invoked but before the return value is handled. * * @author Rossen Stoyanchev * @since 3.1 + * @see #invokeAndHandle(NativeWebRequest, ModelAndViewContainer, Object...) */ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod { @@ -65,25 +68,23 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod { if (annotation != null) { this.responseStatus = annotation.value(); this.responseReason = annotation.reason(); - } } /** - * Invokes the method and handles the return value through registered {@link HandlerMethodReturnValueHandler}s. - * If the handler method is annotated with {@link ResponseStatus}, the status on the response is set accordingly - * after method invocation but before return value handling. - *

Return value handling may be skipped entirely if the handler method returns a {@code null} (or is a - * {@code void} method) and one of the following other conditions is true: + * Invokes the method and handles the return value through a registered {@link HandlerMethodReturnValueHandler}. + *

Return value handling may be skipped entirely when the method returns {@code null} (also possibly due + * to a {@code void} return type) and one of the following additional conditions is true: *

- *

After the call, use the {@link ModelAndViewContainer} parameter to access model attributes and view selection - * and to determine if view resolution is needed. + *

After the return value is handled, callers of this method can use the {@link ModelAndViewContainer} + * to gain access to model attributes, view selection choices, and to check if view resolution is even needed. * * @param request the current request * @param mavContainer the {@link ModelAndViewContainer} for the current request @@ -131,17 +132,18 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod { } /** - * Does the request qualify as not modified? + * Does the given request qualify as "not modified"? + * @see ServletWebRequest#checkNotModified(long) + * @see ServletWebRequest#checkNotModified(String) */ private boolean isRequestNotModified(NativeWebRequest request) { return ((ServletWebRequest) request).isNotModified(); } /** - * Does the method set the response status? + * Does this method have the response status instruction? */ private boolean hasResponseStatus() { return responseStatus != null; } - } \ No newline at end of file diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/AbstractMessageConverterMethodProcessor.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/AbstractMessageConverterMethodProcessor.java index 8714b45f9f5..3cfd9c0f099 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/AbstractMessageConverterMethodProcessor.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/AbstractMessageConverterMethodProcessor.java @@ -37,6 +37,10 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.HandlerMethodReturnValueHandler; /** + * A base class for resolving method argument values by reading from the body of a request with + * {@link HttpMessageConverter}s and for handling method return values by writing to the response with + * {@link HttpMessageConverter}s. + * * @author Arjen Poutsma * @author Rossen Stoyanchev * @since 3.1 @@ -143,4 +147,4 @@ public abstract class AbstractMessageConverterMethodProcessor return acceptedMediaTypes; } -} +} \ No newline at end of file diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/DefaultMethodReturnValueHandler.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/DefaultMethodReturnValueHandler.java index b42a1c56303..304126364d1 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/DefaultMethodReturnValueHandler.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/DefaultMethodReturnValueHandler.java @@ -31,12 +31,21 @@ import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.annotation.ModelAndViewResolver; /** - * A catch-all {@link HandlerMethodReturnValueHandler} to handle return values not handled by any other return - * value handler. - * - *

This handler should always be last in the order as {@link #supportsReturnType(MethodParameter)} always returns - * {@code true}. An attempt is made to handle the return value through a custom {@link ModelAndViewResolver}s or - * otherwise by treating it as a single model attribute. + * Attempts to handle return value types not recognized by any other {@link HandlerMethodReturnValueHandler}. + * Intended to be used as the last of a list of registered handlers as {@link #supportsReturnType(MethodParameter)} + * always returns {@code true}. + *

Handling takes place in the following order: + *

+ *

Note that {@link ModelAndViewResolver} is supported for backwards compatibility. Since the only way to check + * if it supports a return value type is to try to resolve the return value, a {@link ModelAndViewResolver} can + * only be invoked from here after no other {@link HandlerMethodReturnValueHandler} has recognized the return + * value. To avoid this limitation change the {@link ModelAndViewResolver} to implement + * {@link HandlerMethodReturnValueHandler} instead. * * @author Rossen Stoyanchev * @since 3.1 @@ -65,10 +74,6 @@ public class DefaultMethodReturnValueHandler implements HandlerMethodReturnValue return true; } - public boolean usesResponseArgument(MethodParameter parameter) { - return false; - } - public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/HttpEntityMethodProcessor.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/HttpEntityMethodProcessor.java index cfa7a3eb4b4..f719f2db61b 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/HttpEntityMethodProcessor.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/HttpEntityMethodProcessor.java @@ -40,13 +40,11 @@ import org.springframework.util.Assert; import org.springframework.web.HttpMediaTypeNotSupportedException; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; -import org.springframework.web.method.support.HandlerMethodArgumentResolver; -import org.springframework.web.method.support.HandlerMethodReturnValueHandler; import org.springframework.web.method.support.ModelAndViewContainer; /** - * Implementation of {@link HandlerMethodArgumentResolver} and {@link HandlerMethodReturnValueHandler} - * that supports {@link HttpEntity} and {@link ResponseEntity}. + * Resolves {@link HttpEntity} method argument values. + * Handles {@link HttpEntity} and {@link ResponseEntity} return values. * * @author Arjen Poutsma * @author Rossen Stoyanchev @@ -68,27 +66,16 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro return HttpEntity.class.equals(parameterType) || ResponseEntity.class.equals(parameterType); } - public boolean usesResponseArgument(MethodParameter parameterOrReturnType) { - // only when HttpEntity or ResponseEntity is used as a return type - return parameterOrReturnType.getParameterIndex() == -1; - } - public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws IOException, HttpMediaTypeNotSupportedException { + HttpInputMessage inputMessage = createInputMessage(webRequest); Class paramType = getHttpEntityType(parameter); Object body = readWithMessageConverters(webRequest, parameter, paramType); - HttpInputMessage inputMessage = createInputMessage(webRequest); return new HttpEntity(body, inputMessage.getHeaders()); } - - @Override - protected HttpInputMessage createInputMessage(NativeWebRequest webRequest) { - HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); - return new ServletServerHttpRequest(servletRequest); - } private Class getHttpEntityType(MethodParameter methodParam) { Assert.isAssignable(HttpEntity.class, methodParam.getParameterType()); @@ -109,7 +96,12 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro } throw new IllegalArgumentException( "HttpEntity parameter (" + methodParam.getParameterName() + ") is not parameterized"); - + } + + @Override + protected HttpInputMessage createInputMessage(NativeWebRequest webRequest) { + HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); + return new ServletServerHttpRequest(servletRequest); } public void handleReturnValue(Object returnValue, @@ -150,4 +142,5 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro HttpServletResponse servletResponse = (HttpServletResponse) webRequest.getNativeResponse(); return new ServletServerHttpResponse(servletResponse); } -} + +} \ No newline at end of file diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ModelAndViewMethodReturnValueHandler.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ModelAndViewMethodReturnValueHandler.java index 3166c21dfc6..d99efd844f7 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ModelAndViewMethodReturnValueHandler.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ModelAndViewMethodReturnValueHandler.java @@ -23,7 +23,9 @@ import org.springframework.web.method.support.ModelAndViewContainer; import org.springframework.web.servlet.ModelAndView; /** - * Handles {@link ModelAndView} return values. + * Handles return values of type {@link ModelAndView} transferring their content to the {@link ModelAndViewContainer}. + * If the return value is {@code null}, the {@link ModelAndViewContainer#setResolveView(boolean)} flag is set to + * {@code false} to indicate view resolution is not needed. * * @author Rossen Stoyanchev * @since 3.1 @@ -34,10 +36,6 @@ public class ModelAndViewMethodReturnValueHandler implements HandlerMethodReturn return ModelAndView.class.isAssignableFrom(returnType.getParameterType()); } - public boolean usesResponseArgument(MethodParameter parameter) { - return false; - } - public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, @@ -53,4 +51,4 @@ public class ModelAndViewMethodReturnValueHandler implements HandlerMethodReturn } } -} +} \ No newline at end of file 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 518a1248d17..00799c6e63b 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 @@ -20,28 +20,33 @@ import java.util.Map; import javax.servlet.ServletException; -import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.core.MethodParameter; +import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.PathVariable; 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.HandlerMethodArgumentResolver; import org.springframework.web.servlet.HandlerMapping; /** - * Implementation of {@link HandlerMethodArgumentResolver} that supports arguments annotated with - * {@link PathVariable @PathVariable}. + * Resolves method arguments annotated with an @{@link PathVariable}. * + *

An @{@link PathVariable} is a named value that gets resolved from a URI template variable. It is always + * required and does not have a default value to fall back on. See the base class + * {@link AbstractNamedValueMethodArgumentResolver} for more information on how named values are processed. + * + *

A {@link WebDataBinder} is invoked to apply type conversion to resolved path variable values that + * don't yet match the method parameter type. + * * @author Rossen Stoyanchev * @author Arjen Poutsma * @since 3.1 */ public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver { - public PathVariableMethodArgumentResolver(ConfigurableBeanFactory beanFactory) { - super(beanFactory); + public PathVariableMethodArgumentResolver() { + super(null); } public boolean supportsParameter(MethodParameter parameter) { @@ -56,16 +61,16 @@ public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethod @Override @SuppressWarnings("unchecked") - protected Object resolveNamedValueArgument(NativeWebRequest webRequest, MethodParameter parameter, String name) - throws Exception { - Map uriTemplateVariables = (Map) webRequest.getAttribute( - HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST); - return (uriTemplateVariables != null) ? uriTemplateVariables.get(name) : null; + protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception { + String key = HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE; + int scope = RequestAttributes.SCOPE_REQUEST; + Map uriTemplateVars = (Map) request.getAttribute(key, scope); + return (uriTemplateVars != null) ? uriTemplateVars.get(name) : null; } @Override protected void handleMissingValue(String name, MethodParameter parameter) throws ServletException { - throw new IllegalStateException("Could not find @PathVariable [" + name + "] in @RequestMapping"); + throw new IllegalStateException("Could not find the URL template variable [" + name + "]"); } private static class PathVariableNamedValueInfo extends NamedValueInfo { @@ -74,6 +79,4 @@ public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethod super(annotation.value(), true, ValueConstants.DEFAULT_NONE); } } - - -} +} \ No newline at end of file diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/RequestResponseBodyMethodProcessor.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/RequestResponseBodyMethodProcessor.java index dc8795d6e68..90658a1e1b0 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/RequestResponseBodyMethodProcessor.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/RequestResponseBodyMethodProcessor.java @@ -34,13 +34,11 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; -import org.springframework.web.method.support.HandlerMethodArgumentResolver; -import org.springframework.web.method.support.HandlerMethodReturnValueHandler; import org.springframework.web.method.support.ModelAndViewContainer; /** - * Implementation of {@link HandlerMethodArgumentResolver} and {@link HandlerMethodReturnValueHandler} that supports - * parameters annotated with {@link RequestBody} and return values annotated with {@link ResponseBody}. + * Resolves method arguments annotated with @{@link RequestBody}. + * Handles return values from methods annotated with @{@link ResponseBody}. * * @author Arjen Poutsma * @author Rossen Stoyanchev @@ -60,11 +58,6 @@ public class RequestResponseBodyMethodProcessor extends AbstractMessageConverter return returnType.getMethodAnnotation(ResponseBody.class) != null; } - public boolean usesResponseArgument(MethodParameter parameterOrReturnType) { - return parameterOrReturnType.getParameterIndex() == -1 && - parameterOrReturnType.getMethodAnnotation(ResponseBody.class) != null; - } - public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletCookieValueMethodArgumentResolver.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletCookieValueMethodArgumentResolver.java index f49fea83209..b505c69ca81 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletCookieValueMethodArgumentResolver.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletCookieValueMethodArgumentResolver.java @@ -22,35 +22,41 @@ import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.core.MethodParameter; import org.springframework.web.context.request.NativeWebRequest; -import org.springframework.web.method.annotation.support.CookieValueMethodArgumentResolver; +import org.springframework.web.method.annotation.support.AbstractCookieValueMethodArgumentResolver; +import org.springframework.web.util.UrlPathHelper; import org.springframework.web.util.WebUtils; /** - * A {@link CookieValueMethodArgumentResolver} for Servlet environments. + * A {@link AbstractCookieValueMethodArgumentResolver} that resolves the cookie value through the {@link HttpServletRequest}. * * @author Rossen Stoyanchev * @since 3.1 */ -public class ServletCookieValueMethodArgumentResolver extends CookieValueMethodArgumentResolver { +public class ServletCookieValueMethodArgumentResolver extends AbstractCookieValueMethodArgumentResolver { + + private UrlPathHelper urlPathHelper = new UrlPathHelper(); public ServletCookieValueMethodArgumentResolver(ConfigurableBeanFactory beanFactory) { super(beanFactory); } + public void setUrlPathHelper(UrlPathHelper urlPathHelper) { + this.urlPathHelper = urlPathHelper; + } + @Override - protected Object resolveNamedValueArgument(NativeWebRequest webRequest, - MethodParameter parameter, - String cookieName) throws Exception { + protected Object resolveName(String cookieName, MethodParameter parameter, NativeWebRequest webRequest) + throws Exception { HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); Cookie cookieValue = WebUtils.getCookie(servletRequest, cookieName); if (Cookie.class.isAssignableFrom(parameter.getParameterType())) { return cookieValue; } else if (cookieValue != null) { - return getUrlPathHelper().decodeRequestString(servletRequest, cookieValue.getValue()); + return this.urlPathHelper.decodeRequestString(servletRequest, cookieValue.getValue()); } else { return null; } } -} +} \ No newline at end of file diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletModelAttributeMethodProcessor.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletModelAttributeMethodProcessor.java index 8a44189da3a..92ce76483c4 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletModelAttributeMethodProcessor.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletModelAttributeMethodProcessor.java @@ -21,11 +21,13 @@ import javax.servlet.ServletRequest; import org.springframework.beans.BeanUtils; import org.springframework.web.bind.ServletRequestDataBinder; import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.annotation.support.ModelAttributeMethodProcessor; /** - * A {@link ModelAttributeMethodProcessor} for Servlet environments. + * A Servlet-specific {@link ModelAttributeMethodProcessor} variant that casts the {@link WebDataBinder} + * instance to {@link ServletRequestDataBinder} prior to invoking data binding. * * @author Rossen Stoyanchev * @since 3.1 @@ -33,13 +35,12 @@ import org.springframework.web.method.annotation.support.ModelAttributeMethodPro public class ServletModelAttributeMethodProcessor extends ModelAttributeMethodProcessor { /** - * Creates a {@link ServletModelAttributeMethodProcessor} instance. - * @param resolveWithoutAnnotations enable default resolution mode in which parameters without - * annotations that aren't simple types (see {@link BeanUtils#isSimpleProperty(Class)}) - * are also treated as model attributes with a default name based on the model attribute type. + * @param useDefaultResolution in default resolution mode a method argument that isn't a simple type, as + * defined in {@link BeanUtils#isSimpleProperty(Class)}, is treated as a model attribute even if it doesn't + * have an @{@link ModelAttribute} annotation with its name derived from the model attribute type. */ - public ServletModelAttributeMethodProcessor(boolean resolveWithoutAnnotations) { - super(resolveWithoutAnnotations); + public ServletModelAttributeMethodProcessor(boolean useDefaultResolution) { + super(useDefaultResolution); } /** diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletRequestMethodArgumentResolver.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletRequestMethodArgumentResolver.java index 27b8b57b17d..38aa461122f 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletRequestMethodArgumentResolver.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletRequestMethodArgumentResolver.java @@ -36,61 +36,74 @@ import org.springframework.web.multipart.MultipartRequest; import org.springframework.web.servlet.support.RequestContextUtils; /** - * Implementation of {@link HandlerMethodArgumentResolver} that supports {@link ServletRequest} and related arguments. + * Resolves request-related method argument values of the following types: + *

    + *
  • {@link WebRequest} + *
  • {@link ServletRequest} + *
  • {@link MultipartRequest} + *
  • {@link HttpSession} + *
  • {@link Principal} + *
  • {@link Locale} + *
  • {@link InputStream} + *
  • {@link Reader} + *
* * @author Arjen Poutsma + * @author Rossen Stoyanchev + * @since 3.1 */ public class ServletRequestMethodArgumentResolver implements HandlerMethodArgumentResolver { public boolean supportsParameter(MethodParameter parameter) { - Class parameterType = parameter.getParameterType(); - return WebRequest.class.isAssignableFrom(parameterType) || - ServletRequest.class.isAssignableFrom(parameterType) || - MultipartRequest.class.isAssignableFrom(parameterType) || - HttpSession.class.isAssignableFrom(parameterType) || Principal.class.isAssignableFrom(parameterType) || - Locale.class.equals(parameterType) || InputStream.class.isAssignableFrom(parameterType) || - Reader.class.isAssignableFrom(parameterType); - } - - public boolean usesResponseArgument(MethodParameter parameter) { - return false; + Class paramType = parameter.getParameterType(); + return WebRequest.class.isAssignableFrom(paramType) || + ServletRequest.class.isAssignableFrom(paramType) || + MultipartRequest.class.isAssignableFrom(paramType) || + HttpSession.class.isAssignableFrom(paramType) || + Principal.class.isAssignableFrom(paramType) || + Locale.class.equals(paramType) || + InputStream.class.isAssignableFrom(paramType) || + Reader.class.isAssignableFrom(paramType); } public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws IOException { - HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); - Class parameterType = parameter.getParameterType(); - - if (WebRequest.class.isAssignableFrom(parameterType)) { + + Class paramType = parameter.getParameterType(); + if (WebRequest.class.isAssignableFrom(paramType)) { return webRequest; } - if (ServletRequest.class.isAssignableFrom(parameterType) || - MultipartRequest.class.isAssignableFrom(parameterType)) { - Object nativeRequest = webRequest.getNativeRequest(parameterType); + + HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); + if (ServletRequest.class.isAssignableFrom(paramType) || MultipartRequest.class.isAssignableFrom(paramType)) { + Object nativeRequest = webRequest.getNativeRequest(paramType); if (nativeRequest == null) { throw new IllegalStateException( - "Current request is not of type [" + parameterType.getName() + "]: " + request); + "Current request is not of type [" + paramType.getName() + "]: " + request); } return nativeRequest; } - else if (HttpSession.class.isAssignableFrom(parameterType)) { + else if (HttpSession.class.isAssignableFrom(paramType)) { return request.getSession(); } - else if (Principal.class.isAssignableFrom(parameterType)) { + else if (Principal.class.isAssignableFrom(paramType)) { return request.getUserPrincipal(); } - else if (Locale.class.equals(parameterType)) { + else if (Locale.class.equals(paramType)) { return RequestContextUtils.getLocale(request); } - else if (InputStream.class.isAssignableFrom(parameterType)) { + else if (InputStream.class.isAssignableFrom(paramType)) { return request.getInputStream(); } - else if (Reader.class.isAssignableFrom(parameterType)) { + else if (Reader.class.isAssignableFrom(paramType)) { return request.getReader(); } - // should not happen - throw new UnsupportedOperationException(); + else { + // should not happen + throw new UnsupportedOperationException(); + } } -} + +} \ No newline at end of file diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletResponseMethodArgumentResolver.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletResponseMethodArgumentResolver.java index 6193abe0cee..e971415fc4c 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletResponseMethodArgumentResolver.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletResponseMethodArgumentResolver.java @@ -28,33 +28,46 @@ import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; +import org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod; /** - * Implementation of {@link HandlerMethodArgumentResolver} that supports {@link ServletResponse} and related arguments. + * Resolves response-related method argument values of types: + *
    + *
  • {@link ServletResponse} + *
  • {@link OutputStream} + *
  • {@link Writer} + *
* * @author Arjen Poutsma + * @author Rossen Stoyanchev + * @since 3.1 */ public class ServletResponseMethodArgumentResolver implements HandlerMethodArgumentResolver { public boolean supportsParameter(MethodParameter parameter) { - Class parameterType = parameter.getParameterType(); - return ServletResponse.class.isAssignableFrom(parameterType) || - OutputStream.class.isAssignableFrom(parameterType) || Writer.class.isAssignableFrom(parameterType); - } - - public boolean usesResponseArgument(MethodParameter parameter) { - return true; + Class paramType = parameter.getParameterType(); + return ServletResponse.class.isAssignableFrom(paramType) + || OutputStream.class.isAssignableFrom(paramType) + || Writer.class.isAssignableFrom(paramType); } + /** + * {@inheritDoc} + *

Sets the {@link ModelAndViewContainer#setResolveView(boolean)} flag to {@code false} to indicate + * that the method signature provides access to the response. If subsequently the underlying method + * returns {@code null}, view resolution will be bypassed. + * @see ServletInvocableHandlerMethod#invokeAndHandle(NativeWebRequest, ModelAndViewContainer, Object...) + */ public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws IOException { + + mavContainer.setResolveView(false); + HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class); Class parameterType = parameter.getParameterType(); - mavContainer.setResolveView(false); - if (ServletResponse.class.isAssignableFrom(parameterType)) { Object nativeResponse = webRequest.getNativeResponse(parameterType); if (nativeResponse == null) { @@ -74,4 +87,5 @@ public class ServletResponseMethodArgumentResolver implements HandlerMethodArgum throw new UnsupportedOperationException(); } } + } diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletWebArgumentResolverAdapter.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletWebArgumentResolverAdapter.java index fdf69b2e3c6..b1787ae5706 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletWebArgumentResolverAdapter.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletWebArgumentResolverAdapter.java @@ -22,15 +22,16 @@ import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.context.request.ServletWebRequest; -import org.springframework.web.method.annotation.support.WebArgumentResolverAdapter; +import org.springframework.web.method.annotation.support.AbstractWebArgumentResolverAdapter; /** - * A Servlet-specific {@link WebArgumentResolverAdapter} that provides access to a {@link NativeWebRequest}. + * A Servlet-specific {@link AbstractWebArgumentResolverAdapter} that creates a {@link NativeWebRequest} + * from {@link ServletRequestAttributes}. * * @author Rossen Stoyanchev * @since 3.1 */ -public class ServletWebArgumentResolverAdapter extends WebArgumentResolverAdapter { +public class ServletWebArgumentResolverAdapter extends AbstractWebArgumentResolverAdapter { public ServletWebArgumentResolverAdapter(WebArgumentResolver adaptee) { super(adaptee); @@ -45,5 +46,4 @@ public class ServletWebArgumentResolverAdapter extends WebArgumentResolverAdapte } return null; } - -} +} \ No newline at end of file diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ViewMethodReturnValueHandler.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ViewMethodReturnValueHandler.java index 67347bb0f6e..2db1978c1bd 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ViewMethodReturnValueHandler.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ViewMethodReturnValueHandler.java @@ -18,12 +18,16 @@ package org.springframework.web.servlet.mvc.method.annotation.support; import org.springframework.core.MethodParameter; import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.annotation.support.ModelAttributeMethodProcessor; import org.springframework.web.method.support.HandlerMethodReturnValueHandler; import org.springframework.web.method.support.ModelAndViewContainer; import org.springframework.web.servlet.View; /** - * Handles {@link View} and view name return values. + * Handles return values that are of type {@link View} or {@link String} (i.e. a logical view name). + *

Since {@link String} return value can be interpeted in multiple ways, this resolver should be ordered + * after return value handlers that recognize annotated return values such as the + * {@link ModelAttributeMethodProcessor} and the {@link RequestResponseBodyMethodProcessor}. * * @author Rossen Stoyanchev * @since 3.1 @@ -35,10 +39,6 @@ public class ViewMethodReturnValueHandler implements HandlerMethodReturnValueHan return (View.class.isAssignableFrom(paramType) || (String.class.equals(paramType))); } - public boolean usesResponseArgument(MethodParameter parameter) { - return false; - } - public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/HttpEntityMethodProcessorTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/HttpEntityMethodProcessorTests.java index 3b3a424a0c5..cdfb90c8a7f 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/HttpEntityMethodProcessorTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/HttpEntityMethodProcessorTests.java @@ -122,15 +122,6 @@ public class HttpEntityMethodProcessorTests { assertFalse("non-ResponseBody return type supported", processor.supportsReturnType(intReturnValue)); } - @Test - public void usesResponseArgument() { - assertFalse("HttpEntity parameter uses response argument", processor.usesResponseArgument(httpEntityParam)); - assertTrue("ResponseBody return type does not use response argument", - processor.usesResponseArgument(responseEntityReturnValue)); - assertTrue("HttpEntity return type does not use response argument", - processor.usesResponseArgument(httpEntityReturnValue)); - } - @Test @SuppressWarnings("unchecked") public void resolveArgument() throws Exception { @@ -146,8 +137,9 @@ public class HttpEntityMethodProcessorTests { replay(messageConverter); HttpEntity result = (HttpEntity) processor.resolveArgument(httpEntityParam, mavContainer, request, null); - assertEquals("Invalid argument", expected, result.getBody()); + assertTrue("The ResolveView flag shouldn't change", mavContainer.isResolveView()); + assertEquals("Invalid argument", expected, result.getBody()); verify(messageConverter); } @@ -164,6 +156,7 @@ public class HttpEntityMethodProcessorTests { processor.resolveArgument(httpEntityParam, mavContainer, request, null); + assertTrue("The ResolveView flag shouldn't change", mavContainer.isResolveView()); verify(messageConverter); } 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 45440b5ac55..bf6a06d3731 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 @@ -52,7 +52,7 @@ public class PathVariableMethodArgumentResolverTests { @Before public void setUp() throws Exception { - resolver = new PathVariableMethodArgumentResolver(null); + resolver = new PathVariableMethodArgumentResolver(); Method method = getClass().getMethod("handle", String.class, String.class); pathVarParam = new MethodParameter(method, 0); stringParam = new MethodParameter(method, 1); @@ -62,11 +62,6 @@ public class PathVariableMethodArgumentResolverTests { webRequest = new ServletWebRequest(servletRequest, servletResponse); } - @Test - public void usesResponseArgument() { - assertFalse(resolver.usesResponseArgument(null)); - } - @Test public void supportsParameter() { assertTrue("Parameter with @PathVariable annotation", resolver.supportsParameter(pathVarParam)); diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/RequestResponseBodyMethodProcessorTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/RequestResponseBodyMethodProcessorTests.java index 016a222f2ed..4c770f6539e 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/RequestResponseBodyMethodProcessorTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/RequestResponseBodyMethodProcessorTests.java @@ -106,13 +106,6 @@ public class RequestResponseBodyMethodProcessorTests { assertFalse("non-ResponseBody return type supported", processor.supportsReturnType(intReturnValue)); } - @Test - public void usesResponseArgument() { - assertFalse("RequestBody parameter uses response argument", processor.usesResponseArgument(stringParameter)); - assertTrue("ResponseBody return type does not use response argument", - processor.usesResponseArgument(stringReturnValue)); - } - @Test public void resolveArgument() throws Exception { MediaType contentType = MediaType.TEXT_PLAIN; @@ -127,8 +120,9 @@ public class RequestResponseBodyMethodProcessorTests { replay(messageConverter); Object result = processor.resolveArgument(stringParameter, mavContainer, webRequest, null); - assertEquals("Invalid argument", expected, result); + assertEquals("Invalid argument", expected, result); + assertTrue("The ResolveView flag shouldn't change", mavContainer.isResolveView()); verify(messageConverter); } @@ -146,6 +140,7 @@ public class RequestResponseBodyMethodProcessorTests { processor.resolveArgument(stringParameter, mavContainer, webRequest, null); + assertTrue("The ResolveView flag shouldn't change", mavContainer.isResolveView()); verify(messageConverter); } @@ -168,7 +163,7 @@ public class RequestResponseBodyMethodProcessorTests { processor.handleReturnValue(returnValue, stringReturnValue, mavContainer, webRequest); - assertFalse(mavContainer.isResolveView()); + assertFalse("The ResolveView flag wasn't turned off", mavContainer.isResolveView()); verify(messageConverter); } @@ -186,7 +181,7 @@ public class RequestResponseBodyMethodProcessorTests { processor.handleReturnValue(returnValue, stringReturnValue, mavContainer, webRequest); - assertFalse(mavContainer.isResolveView()); + assertFalse("The ResolveView flag wasn't turned off", mavContainer.isResolveView()); verify(messageConverter); } diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletCookieValueMethodArgumentResolverTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletCookieValueMethodArgumentResolverTests.java index f9badf04c33..9a07b80ff0a 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletCookieValueMethodArgumentResolverTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletCookieValueMethodArgumentResolverTests.java @@ -31,7 +31,7 @@ import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.web.bind.annotation.CookieValue; import org.springframework.web.context.request.ServletWebRequest; -import org.springframework.web.method.annotation.support.CookieValueMethodArgumentResolver; +import org.springframework.web.method.annotation.support.AbstractCookieValueMethodArgumentResolver; import org.springframework.web.servlet.mvc.method.annotation.support.ServletCookieValueMethodArgumentResolver; /** @@ -39,7 +39,7 @@ import org.springframework.web.servlet.mvc.method.annotation.support.ServletCook */ public class ServletCookieValueMethodArgumentResolverTests { - private CookieValueMethodArgumentResolver resolver; + private ServletCookieValueMethodArgumentResolver resolver; private MethodParameter cookieParameter; @@ -65,11 +65,6 @@ public class ServletCookieValueMethodArgumentResolverTests { } - @Test - public void usesResponseArgument() throws NoSuchMethodException { - assertFalse("resolver uses response argument", resolver.usesResponseArgument(null)); - } - @Test public void supportsParameter() { assertTrue("Cookie parameter not supported", resolver.supportsParameter(cookieParameter)); diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletRequestMethodArgumentResolverTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletRequestMethodArgumentResolverTests.java index 5748cf7a6b5..ebdadb211e8 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletRequestMethodArgumentResolverTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletRequestMethodArgumentResolverTests.java @@ -33,6 +33,7 @@ import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockHttpSession; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.context.request.WebRequest; +import org.springframework.web.method.support.ModelAndViewContainer; import org.springframework.web.multipart.MultipartRequest; import org.springframework.web.servlet.mvc.method.annotation.support.ServletRequestMethodArgumentResolver; @@ -47,6 +48,8 @@ public class ServletRequestMethodArgumentResolverTests { private Method supportedParams; + private ModelAndViewContainer mavContainer; + private ServletWebRequest webRequest; private MockHttpServletRequest servletRequest; @@ -57,23 +60,21 @@ public class ServletRequestMethodArgumentResolverTests { supportedParams = getClass() .getMethod("supportedParams", ServletRequest.class, MultipartRequest.class, HttpSession.class, Principal.class, Locale.class, InputStream.class, Reader.class, WebRequest.class); + mavContainer = new ModelAndViewContainer(); servletRequest = new MockHttpServletRequest(); webRequest = new ServletWebRequest(servletRequest, new MockHttpServletResponse()); } - @Test - public void usesResponseArgument() { - assertFalse("resolver uses response argument", resolver.usesResponseArgument(null)); - } - @Test public void servletRequest() throws Exception { MethodParameter servletRequestParameter = new MethodParameter(supportedParams, 0); - - assertTrue("ServletRequest not supported", resolver.supportsParameter(servletRequestParameter)); - - Object result = resolver.resolveArgument(servletRequestParameter, null, webRequest, null); + + boolean isSupported = resolver.supportsParameter(servletRequestParameter); + Object result = resolver.resolveArgument(servletRequestParameter, mavContainer, webRequest, null); + + assertTrue("ServletRequest not supported", isSupported); assertSame("Invalid result", servletRequest, result); + assertTrue("The ResolveView flag shouldn't change", mavContainer.isResolveView()); } @Test @@ -82,10 +83,12 @@ public class ServletRequestMethodArgumentResolverTests { servletRequest.setSession(session); MethodParameter sessionParameter = new MethodParameter(supportedParams, 2); - assertTrue("Session not supported", resolver.supportsParameter(sessionParameter)); + boolean isSupported = resolver.supportsParameter(sessionParameter); + Object result = resolver.resolveArgument(sessionParameter, mavContainer, webRequest, null); - Object result = resolver.resolveArgument(sessionParameter, null, webRequest, null); + assertTrue("Session not supported", isSupported); assertSame("Invalid result", session, result); + assertTrue("The ResolveView flag shouldn't change", mavContainer.isResolveView()); } @Test diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletResponseMethodArgumentResolverTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletResponseMethodArgumentResolverTests.java index 7f32054e815..059f6d68331 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletResponseMethodArgumentResolverTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletResponseMethodArgumentResolverTests.java @@ -57,11 +57,6 @@ public class ServletResponseMethodArgumentResolverTests { webRequest = new ServletWebRequest(new MockHttpServletRequest(), servletResponse); } - @Test - public void usesResponseArgument() { - assertTrue("resolver uses response argument", resolver.usesResponseArgument(null)); - } - @Test public void servletResponse() throws Exception { MethodParameter servletResponseParameter = new MethodParameter(supportedParams, 0); diff --git a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/CookieValueMethodArgumentResolver.java b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/AbstractCookieValueMethodArgumentResolver.java similarity index 55% rename from org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/CookieValueMethodArgumentResolver.java rename to org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/AbstractCookieValueMethodArgumentResolver.java index 8cdd58d2a83..6906eb695e1 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/CookieValueMethodArgumentResolver.java +++ b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/AbstractCookieValueMethodArgumentResolver.java @@ -18,33 +18,34 @@ package org.springframework.web.method.annotation.support; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.core.MethodParameter; +import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.CookieValue; -import org.springframework.web.context.request.NativeWebRequest; -import org.springframework.web.method.support.HandlerMethodArgumentResolver; -import org.springframework.web.util.UrlPathHelper; /** - * Implementation of {@link HandlerMethodArgumentResolver} that supports arguments annotated with - * {@link CookieValue @CookieValue}. - * + * A base abstract class to resolve method arguments annotated with @{@link CookieValue}. Subclasses must define how + * to extract the cookie value from the request. + * + *

An @{@link CookieValue} is a named value that is resolved from a cookie. It has a required flag and a + * default value to fall back on when the cookie does not exist. See the base class + * {@link AbstractNamedValueMethodArgumentResolver} for more information on how named values are processed. + * + *

A {@link WebDataBinder} is invoked to apply type conversion to resolved cookie values that don't yet match + * the method parameter type. + * * @author Arjen Poutsma + * @author Rossen Stoyanchev + * @since 3.1 */ -public class CookieValueMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver { +public abstract class AbstractCookieValueMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver { - private UrlPathHelper urlPathHelper = new UrlPathHelper(); - - public CookieValueMethodArgumentResolver(ConfigurableBeanFactory beanFactory) { + /** + * @param beanFactory a bean factory to use for resolving ${...} placeholder and #{...} SpEL expressions + * in default values, or {@code null} if default values are not expected to contain expressions + */ + public AbstractCookieValueMethodArgumentResolver(ConfigurableBeanFactory beanFactory) { super(beanFactory); } - public UrlPathHelper getUrlPathHelper() { - return urlPathHelper; - } - - public void setUrlPathHelper(UrlPathHelper urlPathHelper) { - this.urlPathHelper = urlPathHelper; - } - public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(CookieValue.class); } @@ -55,18 +56,11 @@ public class CookieValueMethodArgumentResolver extends AbstractNamedValueMethodA return new CookieValueNamedValueInfo(annotation); } - @Override - protected Object resolveNamedValueArgument(NativeWebRequest webRequest, - MethodParameter parameter, - String cookieName) throws Exception { - - throw new UnsupportedOperationException("@CookieValue not supported"); - } - @Override protected void handleMissingValue(String cookieName, MethodParameter parameter) { + String paramTypeName = parameter.getParameterType().getName(); throw new IllegalStateException( - "Missing cookie value '" + cookieName + "' of type [" + parameter.getParameterType().getName() + "]"); + "Missing cookie named '" + cookieName + "' for method parameter type [" + paramTypeName + "]"); } private static class CookieValueNamedValueInfo extends NamedValueInfo { @@ -75,4 +69,4 @@ public class CookieValueMethodArgumentResolver extends AbstractNamedValueMethodA super(annotation.value(), annotation.required(), annotation.defaultValue()); } } -} +} \ No newline at end of file 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 a783f3761d4..584829d0dac 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 @@ -25,6 +25,7 @@ import org.springframework.beans.factory.config.BeanExpressionContext; import org.springframework.beans.factory.config.BeanExpressionResolver; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.core.MethodParameter; +import org.springframework.util.Assert; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.ValueConstants; import org.springframework.web.bind.support.WebDataBinderFactory; @@ -34,8 +35,19 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; /** - * Abstract base class for argument resolvers that resolve named values. - * + * Abstract base class for resolving method arguments from a named value. Request parameters, request headers, and + * path variables are examples of named values. Each may have a name, a required flag, and a default value. + *

Subclasses define how to do the following: + *

    + *
  • Obtain named value information for a method parameter + *
  • Resolve names into argument values + *
  • Handle missing argument values when argument values are required + *
+ *

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. + *

A {@link WebDataBinder} is created to apply type conversion to the resolved argument value if it doesn't + * match the method parameter type. + * * @author Arjen Poutsma * @author Rossen Stoyanchev * @since 3.1 @@ -49,15 +61,15 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle private Map namedValueInfoCache = new ConcurrentHashMap(); + /** + * @param beanFactory a bean factory to use for resolving ${...} placeholder and #{...} SpEL expressions + * in default values, or {@code null} if default values are not expected to contain expressions + */ public AbstractNamedValueMethodArgumentResolver(ConfigurableBeanFactory beanFactory) { this.beanFactory = beanFactory; this.expressionContext = (beanFactory != null) ? new BeanExpressionContext(beanFactory, new RequestScope()) : null; } - public boolean usesResponseArgument(MethodParameter parameter) { - return false; - } - public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @@ -66,7 +78,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle NamedValueInfo namedValueInfo = getNamedValueInfo(parameter); - Object arg = resolveNamedValueArgument(webRequest, parameter, namedValueInfo.name); + Object arg = resolveName(namedValueInfo.name, parameter, webRequest); if (arg == null) { if (namedValueInfo.defaultValue != null) { @@ -87,74 +99,73 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle } } + /** + * Obtain the named value for the given method parameter. + */ private NamedValueInfo getNamedValueInfo(MethodParameter parameter) { - NamedValueInfo result = namedValueInfoCache.get(parameter); - if (result == null) { - NamedValueInfo info = createNamedValueInfo(parameter); - String name = info.name; - if (name.length() == 0) { - name = parameter.getParameterName(); - if (name == null) { - throw new IllegalStateException("No parameter name specified for argument of type [" + - parameter.getParameterType().getName() + - "], and no parameter name information found in class file either."); - } - } - boolean required = info.required; - String defaultValue = (ValueConstants.DEFAULT_NONE.equals(info.defaultValue) ? null : info.defaultValue); - - result = new NamedValueInfo(name, required, defaultValue); - namedValueInfoCache.put(parameter, result); + NamedValueInfo namedValueInfo = namedValueInfoCache.get(parameter); + if (namedValueInfo == null) { + namedValueInfo = createNamedValueInfo(parameter); + namedValueInfo = updateNamedValueInfo(parameter, namedValueInfo); + namedValueInfoCache.put(parameter, namedValueInfo); } - return result; + return namedValueInfo; } /** - * Creates a new {@link NamedValueInfo} object for the given method parameter. - * - *

Implementations typically retrieve the method annotation by means of {@link - * MethodParameter#getParameterAnnotation(Class)}. - * + * Create the {@link NamedValueInfo} object for the given method parameter. Implementations typically + * retrieve the method annotation by means of {@link MethodParameter#getParameterAnnotation(Class)}. + * * @param parameter the method parameter * @return the named value information */ protected abstract NamedValueInfo createNamedValueInfo(MethodParameter parameter); /** - * Resolves the given parameter into a method argument. + * Create a new NamedValueInfo based on the given NamedValueInfo with sanitized values. + */ + private NamedValueInfo updateNamedValueInfo(MethodParameter parameter, NamedValueInfo info) { + String name = info.name; + if (info.name.length() == 0) { + name = parameter.getParameterName(); + Assert.notNull(name, "Name for argument type [" + parameter.getParameterType().getName() + + "] not available, and parameter name information not found in class file either."); + } + String defaultValue = (ValueConstants.DEFAULT_NONE.equals(info.defaultValue) ? null : info.defaultValue); + return new NamedValueInfo(name, info.required, defaultValue); + } + + /** + * Resolves the given parameter type and value name into an argument value. + * @param name the name of the value being resolved + * @param parameter the method parameter to resolve to an argument value + * @param request the current request * - * @param webRequest the current web request, allowing access to the native request as well - * @param parameter the parameter to resolve to an argument. This parameter must have previously been passed to the - * {@link #supportsParameter(org.springframework.core.MethodParameter)} method of this interface, which must have - * returned {@code true}. - * @param name the name - * @return the resolved argument. May be {@code null}. + * @return the resolved argument. May be {@code null} * @throws Exception in case of errors */ - protected abstract Object resolveNamedValueArgument(NativeWebRequest webRequest, - MethodParameter parameter, - String name) throws Exception; + protected abstract Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) + throws Exception; - private Object resolveDefaultValue(String value) { + /** + * Resolves the given default value into an argument value. + */ + private Object resolveDefaultValue(String defaultValue) { if (beanFactory == null) { - return value; + return defaultValue; } - String placeholdersResolved = beanFactory.resolveEmbeddedValue(value); + String placeholdersResolved = beanFactory.resolveEmbeddedValue(defaultValue); BeanExpressionResolver exprResolver = beanFactory.getBeanExpressionResolver(); if (exprResolver == null) { - return value; + return defaultValue; } return exprResolver.evaluate(placeholdersResolved, expressionContext); } /** - * Invoked when a named value is required, but - * {@link #resolveNamedValueArgument(NativeWebRequest, MethodParameter, String)} returned {@code null} - * and there is no default value set. - * - *

Concrete subclasses typically throw an exception in this scenario. - * - * @param name the name + * Invoked when a named value is required, but {@link #resolveName(String, MethodParameter, NativeWebRequest)} + * returned {@code null} and there is no default value. Subclasses typically throw an exception in this case. + * @param name the name for the value * @param parameter the method parameter */ protected abstract void handleMissingValue(String name, MethodParameter parameter) throws ServletException; @@ -189,7 +200,5 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle this.required = required; this.defaultValue = defaultValue; } - } - -} +} \ No newline at end of file diff --git a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/WebArgumentResolverAdapter.java b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/AbstractWebArgumentResolverAdapter.java similarity index 59% rename from org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/WebArgumentResolverAdapter.java rename to org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/AbstractWebArgumentResolverAdapter.java index fd2f30d2090..36a883332c2 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/WebArgumentResolverAdapter.java +++ b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/AbstractWebArgumentResolverAdapter.java @@ -21,32 +21,48 @@ import org.apache.commons.logging.LogFactory; import org.springframework.core.MethodParameter; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; +import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.support.WebArgumentResolver; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; -import org.springframework.web.context.request.RequestAttributes; -import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; /** - * Adapts a {@link WebArgumentResolver} into the {@link HandlerMethodArgumentResolver} contract. + * An abstract base class adapting a {@link WebArgumentResolver} into the {@link HandlerMethodArgumentResolver} + * contract. Provided for backwards compatibility, some important considerations are listed below. + * + *

The method {@link #supportsParameter(MethodParameter)} is implemented by trying to resolve the value through + * the {@link WebArgumentResolver} and verifying the resulting value is not {@link WebArgumentResolver#UNRESOLVED}. + * Exceptions resulting from that are absorbed and ignored since the adapter can't be sure if this is the resolver + * that supports the method parameter or not. To avoid this limitation change the {@link WebArgumentResolver} to + * implement the {@link HandlerMethodArgumentResolver} contract instead. + * + *

Another potentially useful advantage of {@link HandlerMethodArgumentResolver} is that it provides access to + * model attributes through the {@link ModelAndViewContainer} as well as access to a {@link WebDataBinderFactory} + * for when type conversion through a {@link WebDataBinder} is needed. * * @author Arjen Poutsma * @author Rossen Stoyanchev * @since 3.1 */ -public class WebArgumentResolverAdapter implements HandlerMethodArgumentResolver { +public abstract class AbstractWebArgumentResolverAdapter implements HandlerMethodArgumentResolver { private final Log logger = LogFactory.getLog(this.getClass()); private final WebArgumentResolver adaptee; - public WebArgumentResolverAdapter(WebArgumentResolver adaptee) { + /** + * Create a {@link AbstractWebArgumentResolverAdapter} with the {@link WebArgumentResolver} instance to delegate to. + */ + public AbstractWebArgumentResolverAdapter(WebArgumentResolver adaptee) { Assert.notNull(adaptee, "'adaptee' must not be null"); this.adaptee = adaptee; } + /** + * See the class-level documentation for an important consideration about exceptions arising in this method. + */ public boolean supportsParameter(MethodParameter parameter) { try { NativeWebRequest webRequest = getWebRequest(); @@ -64,16 +80,17 @@ public class WebArgumentResolverAdapter implements HandlerMethodArgumentResolver return false; } } - - protected NativeWebRequest getWebRequest() { - RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); - return (requestAttributes instanceof NativeWebRequest) ? (NativeWebRequest) requestAttributes : null; - } - public boolean usesResponseArgument(MethodParameter parameter) { - return false; - } + /** + * Provide access to a {@link NativeWebRequest}. + */ + protected abstract NativeWebRequest getWebRequest(); + /** + * Resolves the argument value by delegating to the {@link WebArgumentResolver} instance. + * @exception IllegalStateException if the resolved value is {@link WebArgumentResolver#UNRESOLVED} or if the + * return value type cannot be assigned to the method parameter type. + */ public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @@ -88,4 +105,4 @@ public class WebArgumentResolverAdapter implements HandlerMethodArgumentResolver } return result; } -} +} \ No newline at end of file diff --git a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/ErrorsMethodArgumentResolver.java b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/ErrorsMethodArgumentResolver.java index d5e2ff2515e..b6bb298ca3e 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/ErrorsMethodArgumentResolver.java +++ b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/ErrorsMethodArgumentResolver.java @@ -23,18 +23,19 @@ import org.springframework.core.MethodParameter; import org.springframework.ui.ModelMap; import org.springframework.validation.BindingResult; import org.springframework.validation.Errors; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; /** - * An implementation of {@link HandlerMethodArgumentResolver} that resolves {@link Errors} method parameters. - * Such parameters must be preceded by {@link ModelAttribute} parameters as described in {@link RequestMapping}. + * Resolves method arguments of type {@link Errors} and {@link BindingResult}. + * + *

This argument should appear after a model attribute argument in the signature of the handler method. + * It is resolved by accessing the last attribute in the model expecting that to be a {@link BindingResult}. * * @author Rossen Stoyanchev + * @since 3.1 */ public class ErrorsMethodArgumentResolver implements HandlerMethodArgumentResolver { @@ -43,10 +44,6 @@ public class ErrorsMethodArgumentResolver implements HandlerMethodArgumentResolv return Errors.class.isAssignableFrom(paramType); } - public boolean usesResponseArgument(MethodParameter parameter) { - return false; - } - public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @@ -67,5 +64,4 @@ public class ErrorsMethodArgumentResolver implements HandlerMethodArgumentResolv private boolean isBindingResultKey(String key) { return key.startsWith(BindingResult.MODEL_KEY_PREFIX); } - -} +} \ No newline at end of file diff --git a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/ExpressionValueMethodArgumentResolver.java b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/ExpressionValueMethodArgumentResolver.java index 2602e785681..0a826dc3b36 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/ExpressionValueMethodArgumentResolver.java +++ b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/ExpressionValueMethodArgumentResolver.java @@ -21,18 +21,28 @@ import javax.servlet.ServletException; import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.core.MethodParameter; +import org.springframework.web.bind.WebDataBinder; import org.springframework.web.context.request.NativeWebRequest; -import org.springframework.web.method.support.HandlerMethodArgumentResolver; /** - * Implementation of {@link HandlerMethodArgumentResolver} that supports arguments annotated - * with {@link Value @Value}. + * Resolves method arguments annotated with @{@link Value}. + * + *

An @{@link Value} is a named value that does not have a name but gets resolved from a default value string + * that may contain ${...} placeholder or Spring Expression Language #{...} expressions. See the base class + * {@link AbstractNamedValueMethodArgumentResolver} for more information on how named values are processed. + * + *

A {@link WebDataBinder} is invoked to apply type conversion to resolved argument values that don't yet match + * the method parameter type. * * @author Rossen Stoyanchev * @since 3.1 */ public class ExpressionValueMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver { + /** + * @param beanFactory a bean factory to use for resolving ${...} placeholder and #{...} SpEL expressions + * in default values, or {@code null} if default values are not expected to contain expressions + */ public ExpressionValueMethodArgumentResolver(ConfigurableBeanFactory beanFactory) { super(beanFactory); } @@ -48,16 +58,15 @@ public class ExpressionValueMethodArgumentResolver extends AbstractNamedValueMet } @Override - protected Object resolveNamedValueArgument(NativeWebRequest webRequest, MethodParameter parameter, String name) + protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest webRequest) throws Exception { - // Only interested in default value resolution + // There is no name to be resolved return null; } @Override protected void handleMissingValue(String name, MethodParameter parameter) throws ServletException { - // Should not happen - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Did not expect to handle a missing value: an @Value is never required"); } private static class ExpressionValueNamedValueInfo extends NamedValueInfo { @@ -65,6 +74,5 @@ public class ExpressionValueMethodArgumentResolver extends AbstractNamedValueMet private ExpressionValueNamedValueInfo(Value annotation) { super("@Value", false, annotation.value()); } - } - -} + } +} \ No newline at end of file diff --git a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/ModelAttributeMethodProcessor.java b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/ModelAttributeMethodProcessor.java index 683753e9bde..46e756a0fce 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/ModelAttributeMethodProcessor.java +++ b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/ModelAttributeMethodProcessor.java @@ -21,6 +21,7 @@ import java.lang.annotation.Annotation; import org.springframework.beans.BeanUtils; import org.springframework.core.MethodParameter; import org.springframework.validation.BindException; +import org.springframework.validation.BindingResult; import org.springframework.validation.DataBinder; import org.springframework.validation.Errors; import org.springframework.web.bind.WebDataBinder; @@ -34,24 +35,30 @@ import org.springframework.web.method.support.HandlerMethodReturnValueHandler; import org.springframework.web.method.support.ModelAndViewContainer; /** - * Resolves model attribute method parameters. + * Resolves method arguments annotated with @{@link ModelAttribute}. Or if created in default resolution mode, + * resolves any non-simple type argument even without an @{@link ModelAttribute}. See the constructor for details. + * + *

A model attribute argument value is obtained from the model or is created using its default constructor. + * Data binding and optionally validation is then applied through a {@link WebDataBinder} instance. Validation is + * invoked optionally when the argument is annotated with an {@code @Valid}. + * + *

Also handles return values from methods annotated with an @{@link ModelAttribute}. The return value is + * added to the {@link ModelAndViewContainer}. * * @author Rossen Stoyanchev * @since 3.1 */ -public class ModelAttributeMethodProcessor - implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler { +public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler { - private final boolean resolveArgumentsWithoutAnnotations; + private final boolean useDefaultResolution; /** - * Creates a {@link ModelAttributeMethodProcessor} instance. - * @param resolveArgumentsWithoutAnnotations enable default resolution mode in which arguments without - * annotations that aren't simple types (see {@link BeanUtils#isSimpleProperty(Class)}) - * are also treated as model attributes with a default name based on the model attribute type. + * @param useDefaultResolution in default resolution mode a method argument that isn't a simple type, as + * defined in {@link BeanUtils#isSimpleProperty(Class)}, is treated as a model attribute even if it doesn't + * have an @{@link ModelAttribute} annotation with its name derived from the model attribute type. */ - public ModelAttributeMethodProcessor(boolean resolveArgumentsWithoutAnnotations) { - this.resolveArgumentsWithoutAnnotations = resolveArgumentsWithoutAnnotations; + public ModelAttributeMethodProcessor(boolean useDefaultResolution) { + this.useDefaultResolution = useDefaultResolution; } /** @@ -62,7 +69,7 @@ public class ModelAttributeMethodProcessor if (parameter.hasParameterAnnotation(ModelAttribute.class)) { return true; } - else if (this.resolveArgumentsWithoutAnnotations) { + else if (this.useDefaultResolution) { return !BeanUtils.isSimpleProperty(parameter.getParameterType()); } else { @@ -70,15 +77,13 @@ public class ModelAttributeMethodProcessor } } - public boolean usesResponseArgument(MethodParameter parameter) { - return false; - } - /** - * Resolves the argument to a model attribute creating a {@link WebDataBinder} and invoking data binding on it. - * The model attribute is obtained from the model first or otherwise created via direct instantiation. - * @throws Exception if data binder initialization fails or if data binding results in errors and the next - * method parameter is not of type {@link Errors}. + * Resolves the argument to a model attribute looking up the attribute in the model or instantiating it using its + * default constructor. Data binding and optionally validation is then applied through a {@link WebDataBinder} + * instance. Validation is invoked optionally when the method parameter is annotated with an {@code @Valid}. + * + * @throws Exception if a {@link WebDataBinder} could not be created or if data binding and validation result in + * an error and the next method parameter is not of type {@link Errors} or {@link BindingResult}. */ public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, @@ -164,5 +169,4 @@ public class ModelAttributeMethodProcessor mavContainer.addAttribute(name, returnValue); } } - } \ No newline at end of file diff --git a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/ModelMethodProcessor.java b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/ModelMethodProcessor.java index a135b02e6ef..e53d4592d16 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/ModelMethodProcessor.java +++ b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/ModelMethodProcessor.java @@ -28,7 +28,12 @@ import org.springframework.web.method.support.HandlerMethodReturnValueHandler; import org.springframework.web.method.support.ModelAndViewContainer; /** - * Resolves {@link Model} and {@link Map} method parameters. + * Resolves {@link Map} and {@link Model} method arguments. + * + *

Handles {@link Model} return values adding their attributes to the {@link ModelAndViewContainer}. + * Handles {@link Map} return values in the same way as long as the method does not have an @{@link ModelAttribute}. + * If the method does have an @{@link ModelAttribute}, it is assumed the returned {@link Map} is a model attribute + * and not a model. * * @author Rossen Stoyanchev * @since 3.1 @@ -40,10 +45,6 @@ public class ModelMethodProcessor implements HandlerMethodArgumentResolver, Hand return Model.class.isAssignableFrom(paramType) || Map.class.isAssignableFrom(paramType); } - public boolean usesResponseArgument(MethodParameter parameter) { - return false; - } - public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @@ -78,5 +79,4 @@ public class ModelMethodProcessor implements HandlerMethodArgumentResolver, Hand throw new UnsupportedOperationException(); } } - -} +} \ No newline at end of file diff --git a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/RequestHeaderMapMethodArgumentResolver.java b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/RequestHeaderMapMethodArgumentResolver.java index a55dee18b76..e9f9643f519 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/RequestHeaderMapMethodArgumentResolver.java +++ b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/RequestHeaderMapMethodArgumentResolver.java @@ -31,10 +31,17 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; /** - * Implementation of {@link HandlerMethodArgumentResolver} that supports {@link Map} arguments annotated with - * {@link RequestHeader @RequestHeader}. + * Resolves {@link Map} method arguments annotated with an @{@link RequestHeader}. + * See {@link RequestHeaderMethodArgumentResolver} for individual header values with an @{@link RequestHeader}. + * + *

The created {@link Map} contains all request header name/value pairs. If the method parameter type + * is {@link MultiValueMap} instead, the created map contains all request headers and all their values in case + * request headers have multiple values. * * @author Arjen Poutsma + * @author Rossen Stoyanchev + * @since 3.1 + * @see RequestHeaderMethodArgumentResolver */ public class RequestHeaderMapMethodArgumentResolver implements HandlerMethodArgumentResolver { @@ -43,10 +50,6 @@ public class RequestHeaderMapMethodArgumentResolver implements HandlerMethodArgu && Map.class.isAssignableFrom(parameter.getParameterType()); } - public boolean usesResponseArgument(MethodParameter parameter) { - return false; - } - public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @@ -79,4 +82,4 @@ public class RequestHeaderMapMethodArgumentResolver implements HandlerMethodArgu return result; } } -} +} \ No newline at end of file diff --git a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/RequestHeaderMethodArgumentResolver.java b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/RequestHeaderMethodArgumentResolver.java index 1ff704499be..b03e48dca51 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/RequestHeaderMethodArgumentResolver.java +++ b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/RequestHeaderMethodArgumentResolver.java @@ -20,18 +20,31 @@ import java.util.Map; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.core.MethodParameter; +import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.context.request.NativeWebRequest; -import org.springframework.web.method.support.HandlerMethodArgumentResolver; /** - * Implementation of {@link HandlerMethodArgumentResolver} that supports arguments annotated with - * {@link RequestHeader @RequestHeader}. + * Resolves method arguments annotated with @{@link RequestHeader} with the exception of {@link Map} arguments. + * See {@link RequestHeaderMapMethodArgumentResolver} for {@link Map} arguments annotated with @{@link RequestHeader}. + * + *

An @{@link RequestHeader} is a named value that gets resolved from a request header. It has a required flag + * and a default value to fall back on when the request header does not exist. See the base class + * {@link AbstractNamedValueMethodArgumentResolver} for more information on how named values are processed. * + *

A {@link WebDataBinder} is invoked to apply type conversion to resolved request header values that + * don't yet match the method parameter type. + * * @author Arjen Poutsma + * @author Rossen Stoyanchev + * @since 3.1 */ public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver { + /** + * @param beanFactory a bean factory to use for resolving ${...} placeholder and #{...} SpEL expressions + * in default values, or {@code null} if default values are not expected to contain expressions + */ public RequestHeaderMethodArgumentResolver(ConfigurableBeanFactory beanFactory) { super(beanFactory); } @@ -48,10 +61,8 @@ public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueMetho } @Override - protected Object resolveNamedValueArgument(NativeWebRequest webRequest, - MethodParameter parameter, - String headerName) throws Exception { - String[] headerValues = webRequest.getHeaderValues(headerName); + protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception { + String[] headerValues = request.getHeaderValues(name); if (headerValues != null) { return (headerValues.length == 1 ? headerValues[0] : headerValues); } @@ -62,8 +73,9 @@ public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueMetho @Override protected void handleMissingValue(String headerName, MethodParameter parameter) { + String paramTypeName = parameter.getParameterType().getName(); throw new IllegalStateException( - "Missing header '" + headerName + "' of type [" + parameter.getParameterType().getName() + "]"); + "Missing header '" + headerName + "' for method parameter type [" + paramTypeName + "]"); } private static class RequestHeaderNamedValueInfo extends NamedValueInfo { @@ -72,5 +84,4 @@ public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueMetho super(annotation.value(), annotation.required(), annotation.defaultValue()); } } - -} +} \ No newline at end of file diff --git a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/RequestParamMapMethodArgumentResolver.java b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/RequestParamMapMethodArgumentResolver.java index ffffe22c1e5..6d89e0e0512 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/RequestParamMapMethodArgumentResolver.java +++ b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/RequestParamMapMethodArgumentResolver.java @@ -30,10 +30,18 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; /** - * Implementation of {@link HandlerMethodArgumentResolver} that supports {@link Map} arguments annotated with - * {@link RequestParam @RequestParam}. + * Resolves {@link Map} method arguments annotated with an @{@link RequestParam} where the annotation does not + * specify a request parameter name. See {@link RequestParamMethodArgumentResolver} for resolving {@link Map} + * method arguments with a request parameter name. + * + *

The created {@link Map} contains all request parameter name/value pairs. If the method parameter type + * is {@link MultiValueMap} instead, the created map contains all request parameters and all there values for + * cases where request parameters have multiple values. * * @author Arjen Poutsma + * @author Rossen Stoyanchev + * @since 3.1 + * @see RequestParamMethodArgumentResolver */ public class RequestParamMapMethodArgumentResolver implements HandlerMethodArgumentResolver { @@ -47,10 +55,6 @@ public class RequestParamMapMethodArgumentResolver implements HandlerMethodArgum return false; } - public boolean usesResponseArgument(MethodParameter parameter) { - return false; - } - public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @@ -77,4 +81,4 @@ public class RequestParamMapMethodArgumentResolver implements HandlerMethodArgum return result; } } -} +} \ No newline at end of file diff --git a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/RequestParamMethodArgumentResolver.java b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/RequestParamMethodArgumentResolver.java index 41889d0c604..792d002ba9c 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/RequestParamMethodArgumentResolver.java +++ b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/RequestParamMethodArgumentResolver.java @@ -16,6 +16,7 @@ package org.springframework.web.method.annotation.support; +import java.beans.PropertyEditor; import java.util.List; import java.util.Map; @@ -24,38 +25,51 @@ import javax.servlet.ServletException; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.core.MethodParameter; +import org.springframework.core.convert.converter.Converter; import org.springframework.util.StringUtils; import org.springframework.web.bind.MissingServletRequestParameterException; +import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ValueConstants; import org.springframework.web.context.request.NativeWebRequest; -import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartRequest; /** - * Implementation of {@link HandlerMethodArgumentResolver} that supports arguments annotated with - * {@link RequestParam @RequestParam}. - * + * Resolves method arguments annotated with @{@link RequestParam}. + * + *

If the method parameter type is {@link Map}, the request parameter name is resolved and then converted + * to a {@link Map} via type conversion assuming a suitable {@link PropertyEditor} or {@link Converter} is + * registered. Alternatively, see {@link RequestParamMapMethodArgumentResolver} for access to all request + * parameters in a {@link Map}. + * + *

If this class is created with default resolution mode on, simple types not annotated + * with @{@link RequestParam} are also treated as request parameters with the parameter name based + * on the method argument name. See the class constructor for more details. + * + *

A {@link WebDataBinder} is invoked to apply type conversion to resolved request header values that + * don't yet match the method parameter type. + * * @author Arjen Poutsma * @author Rossen Stoyanchev + * @since 3.1 + * @see RequestParamMapMethodArgumentResolver */ public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver { - private final boolean resolveParamsWithoutAnnotations; + private final boolean useDefaultResolution; /** - * Creates a {@link RequestParamMethodArgumentResolver} instance. - * - * @param beanFactory the bean factory to use for resolving default value expressions - * @param resolveParamsWithoutAnnotations enable default resolution mode in which parameters without - * annotations that are simple types (see {@link BeanUtils#isSimpleProperty(Class)}) - * are also treated as model attributes with a default name based on the method argument name. + * @param beanFactory a bean factory to use for resolving ${...} placeholder and #{...} SpEL expressions + * in default values, or {@code null} if default values are not expected to contain expressions + * @param useDefaultResolution in default resolution mode a method argument that is a simple type, as + * defined in {@link BeanUtils#isSimpleProperty(Class)}, is treated as a request parameter even if it doesn't have + * an @{@link RequestParam} annotation, the request parameter name is derived from the method parameter name. */ public RequestParamMethodArgumentResolver(ConfigurableBeanFactory beanFactory, - boolean resolveParamsWithoutAnnotations) { + boolean useDefaultResolution) { super(beanFactory); - this.resolveParamsWithoutAnnotations = resolveParamsWithoutAnnotations; + this.useDefaultResolution = useDefaultResolution; } public boolean supportsParameter(MethodParameter parameter) { @@ -67,7 +81,7 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethod } return true; } - else if (this.resolveParamsWithoutAnnotations && !parameter.hasParameterAnnotations()) { + else if (this.useDefaultResolution) { return BeanUtils.isSimpleProperty(paramType); } else { @@ -84,18 +98,16 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethod } @Override - protected Object resolveNamedValueArgument(NativeWebRequest webRequest, - MethodParameter parameter, - String paramName) throws Exception { + protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest webRequest) throws Exception { MultipartRequest multipartRequest = webRequest.getNativeRequest(MultipartRequest.class); if (multipartRequest != null) { - List files = multipartRequest.getFiles(paramName); + List files = multipartRequest.getFiles(name); if (!files.isEmpty()) { return (files.size() == 1 ? files.get(0) : files); } } - String[] paramValues = webRequest.getParameterValues(paramName); + String[] paramValues = webRequest.getParameterValues(name); if (paramValues != null) { return paramValues.length == 1 ? paramValues[0] : paramValues; } @@ -119,5 +131,4 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethod super(annotation.value(), annotation.required(), annotation.defaultValue()); } } - -} +} \ No newline at end of file diff --git a/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/ModelMethodProcessorTests.java b/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/ModelMethodProcessorTests.java index d316ab6377d..d904c528fa1 100644 --- a/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/ModelMethodProcessorTests.java +++ b/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/ModelMethodProcessorTests.java @@ -17,7 +17,6 @@ package org.springframework.web.method.annotation.support; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; @@ -69,11 +68,6 @@ public class ModelMethodProcessorTests { this.webRequest = new ServletWebRequest(new MockHttpServletRequest()); } - @Test - public void usesResponseArgument() { - assertFalse(resolver.usesResponseArgument(null)); - } - @Test public void supportsParameter() { assertTrue(resolver.supportsParameter(modelParameter)); diff --git a/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/RequestHeaderMapMethodArgumentResolverTests.java b/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/RequestHeaderMapMethodArgumentResolverTests.java index 3c61fcbee31..48fd3e7784a 100644 --- a/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/RequestHeaderMapMethodArgumentResolverTests.java +++ b/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/RequestHeaderMapMethodArgumentResolverTests.java @@ -35,7 +35,6 @@ import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.ServletWebRequest; -import org.springframework.web.method.annotation.support.RequestHeaderMapMethodArgumentResolver; /** * @author Arjen Poutsma @@ -72,11 +71,6 @@ public class RequestHeaderMapMethodArgumentResolverTests { } - @Test - public void usesResponseArgument() throws NoSuchMethodException { - assertFalse("resolver uses response argument", resolver.usesResponseArgument(null)); - } - @Test public void supportsParameter() { assertTrue("Map parameter not supported", resolver.supportsParameter(mapParameter)); diff --git a/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/RequestHeaderMethodArgumentResolverTests.java b/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/RequestHeaderMethodArgumentResolverTests.java index d72a9f4e825..23ec0101cc0 100644 --- a/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/RequestHeaderMethodArgumentResolverTests.java +++ b/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/RequestHeaderMethodArgumentResolverTests.java @@ -35,7 +35,6 @@ import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.context.support.GenericWebApplicationContext; -import org.springframework.web.method.annotation.support.RequestHeaderMethodArgumentResolver; /** * @author Arjen Poutsma @@ -85,11 +84,6 @@ public class RequestHeaderMethodArgumentResolverTests { RequestContextHolder.resetRequestAttributes(); } - @Test - public void usesResponseArgument() throws NoSuchMethodException { - assertFalse("resolver uses response argument", resolver.usesResponseArgument(null)); - } - @Test public void supportsParameter() { assertTrue("String parameter not supported", resolver.supportsParameter(stringParameter)); diff --git a/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/RequestParamMapMethodArgumentResolverTests.java b/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/RequestParamMapMethodArgumentResolverTests.java index a726603b99d..c77f532244c 100644 --- a/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/RequestParamMapMethodArgumentResolverTests.java +++ b/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/RequestParamMapMethodArgumentResolverTests.java @@ -34,7 +34,6 @@ import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.ServletWebRequest; -import org.springframework.web.method.annotation.support.RequestParamMapMethodArgumentResolver; /** * @author Arjen Poutsma @@ -68,11 +67,6 @@ public class RequestParamMapMethodArgumentResolverTests { } - @Test - public void usesResponseArgument() throws NoSuchMethodException { - assertFalse("resolver uses response argument", resolver.usesResponseArgument(null)); - } - @Test public void supportsParameter() { assertTrue("Map parameter not supported", resolver.supportsParameter(mapParameter)); diff --git a/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/RequestParamMethodArgumentResolverTests.java b/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/RequestParamMethodArgumentResolverTests.java index 43df1086adb..cd0bd5b7038 100644 --- a/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/RequestParamMethodArgumentResolverTests.java +++ b/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/RequestParamMethodArgumentResolverTests.java @@ -36,7 +36,6 @@ import org.springframework.web.bind.MissingServletRequestParameterException; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.ServletWebRequest; -import org.springframework.web.method.annotation.support.RequestParamMethodArgumentResolver; import org.springframework.web.multipart.MultipartFile; /** @@ -82,11 +81,6 @@ public class RequestParamMethodArgumentResolverTests { } - @Test - public void usesResponseArgument() throws NoSuchMethodException { - assertFalse("resolver uses response argument", resolver.usesResponseArgument(null)); - } - @Test public void supportsParameter() { assertTrue("String parameter not supported", resolver.supportsParameter(stringParameter)); @@ -154,8 +148,6 @@ public class RequestParamMethodArgumentResolverTests { @RequestParam(value = "file") MultipartFile file, @RequestParam Map unsupported, String plainParam) { - } - } diff --git a/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/WebArgumentResolverAdapterTests.java b/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/WebArgumentResolverAdapterTests.java index 182a4d89225..ec90e88beff 100644 --- a/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/WebArgumentResolverAdapterTests.java +++ b/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/WebArgumentResolverAdapterTests.java @@ -33,7 +33,6 @@ import org.springframework.web.bind.support.WebArgumentResolver; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletWebRequest; -import org.springframework.web.method.annotation.support.WebArgumentResolverAdapter; /** * @author Arjen Poutsma @@ -42,7 +41,7 @@ public class WebArgumentResolverAdapterTests { private WebArgumentResolver adaptee; - private WebArgumentResolverAdapter adapter; + private TestWebArgumentResolverAdapter adapter; private MethodParameter parameter; @@ -51,7 +50,7 @@ public class WebArgumentResolverAdapterTests { @Before public void setUp() throws Exception { adaptee = createMock(WebArgumentResolver.class); - adapter = new WebArgumentResolverAdapter(adaptee); + adapter = new TestWebArgumentResolverAdapter(adaptee); parameter = new MethodParameter(getClass().getMethod("handle", Integer.TYPE), 0); @@ -162,4 +161,17 @@ public class WebArgumentResolverAdapterTests { public void handle(int param) { } + + private class TestWebArgumentResolverAdapter extends AbstractWebArgumentResolverAdapter { + + public TestWebArgumentResolverAdapter(WebArgumentResolver adaptee) { + super(adaptee); + } + + @Override + protected NativeWebRequest getWebRequest() { + return WebArgumentResolverAdapterTests.this.webRequest; + } + } + }