Support access to all URI vars via @PathVariable Map

Issue: SPR-9289
This commit is contained in:
Rossen Stoyanchev
2012-05-14 16:01:16 -04:00
parent 698d004260
commit 1d0e484eac
8 changed files with 256 additions and 48 deletions

View File

@@ -79,6 +79,9 @@ import java.util.concurrent.Callable;
* will match against the regular expression {@code [^\.]*} (i.e. any character
* other than period), but this can be changed by specifying another regular
* expression, like so: /hotels/{hotel:\d+}.
* Additionally, {@code @PathVariable} can be used on a
* {@link java.util.Map Map<String, String>} to gain access to all
* URI template variables.
* <li>{@link RequestParam @RequestParam} annotated parameters for access to
* specific Servlet/Portlet request parameters. Parameter values will be
* converted to the declared method argument type. Additionally,

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -44,24 +44,25 @@ import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.util.WebUtils;
/**
* Resolves method arguments annotated with @{@link RequestParam}, arguments of
* type {@link MultipartFile} in conjunction with Spring's {@link MultipartResolver}
* abstraction, and arguments of type {@code javax.servlet.http.Part} in conjunction
* with Servlet 3.0 multipart requests. This resolver can also be created in default
* resolution mode in which simple types (int, long, etc.) not annotated
* with @{@link RequestParam} are also treated as request parameters with the
* Resolves method arguments annotated with @{@link RequestParam}, arguments of
* type {@link MultipartFile} in conjunction with Spring's {@link MultipartResolver}
* abstraction, and arguments of type {@code javax.servlet.http.Part} in conjunction
* with Servlet 3.0 multipart requests. This resolver can also be created in default
* resolution mode in which simple types (int, long, etc.) not annotated
* with @{@link RequestParam} are also treated as request parameters with the
* parameter name derived from the argument name.
*
* <p>If the method parameter type is {@link Map}, the request parameter name is used to
* resolve the request parameter String value. The value is then converted to a {@link Map}
* via type conversion assuming a suitable {@link Converter} or {@link PropertyEditor} has
* been registered. If a request parameter name is not specified with a {@link Map} method
* parameter type, the {@link RequestParamMapMethodArgumentResolver} is used instead
* providing access to all request parameters in the form of a map.
*
* <p>A {@link WebDataBinder} is invoked to apply type conversion to resolved request
*
* <p>If the method parameter type is {@link Map}, the name specified in the
* annotation is used to resolve the request parameter String value. The value is
* then converted to a {@link Map} via type conversion assuming a suitable
* {@link Converter} or {@link PropertyEditor} has been registered.
* Or if a request parameter name is not specified the
* {@link RequestParamMapMethodArgumentResolver} is used instead to provide
* access to all request parameters in the form of a map.
*
* <p>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
@@ -72,15 +73,15 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethod
private final boolean useDefaultResolution;
/**
* @param beanFactory a bean factory used for resolving ${...} placeholder
* and #{...} SpEL expressions in default values, or {@code null} if default
* @param beanFactory a bean factory used 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},
* is treated as a request parameter even if it itsn't annotated, the
* @param useDefaultResolution in default resolution mode a method argument
* that is a simple type, as defined in {@link BeanUtils#isSimpleProperty},
* is treated as a request parameter even if it itsn't annotated, the
* request parameter name is derived from the method parameter name.
*/
public RequestParamMethodArgumentResolver(ConfigurableBeanFactory beanFactory,
public RequestParamMethodArgumentResolver(ConfigurableBeanFactory beanFactory,
boolean useDefaultResolution) {
super(beanFactory);
this.useDefaultResolution = useDefaultResolution;
@@ -89,15 +90,15 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethod
/**
* Supports the following:
* <ul>
* <li>@RequestParam-annotated method arguments.
* This excludes {@link Map} params where the annotation doesn't
* specify a name. See {@link RequestParamMapMethodArgumentResolver}
* <li>@RequestParam-annotated method arguments.
* This excludes {@link Map} params where the annotation doesn't
* specify a name. See {@link RequestParamMapMethodArgumentResolver}
* instead for such params.
* <li>Arguments of type {@link MultipartFile}
* <li>Arguments of type {@link MultipartFile}
* unless annotated with @{@link RequestPart}.
* <li>Arguments of type {@code javax.servlet.http.Part}
* <li>Arguments of type {@code javax.servlet.http.Part}
* unless annotated with @{@link RequestPart}.
* <li>In default resolution mode, simple type arguments
* <li>In default resolution mode, simple type arguments
* even if not with @{@link RequestParam}.
* </ul>
*/
@@ -131,8 +132,8 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethod
@Override
protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
RequestParam annotation = parameter.getParameterAnnotation(RequestParam.class);
return (annotation != null) ?
new RequestParamNamedValueInfo(annotation) :
return (annotation != null) ?
new RequestParamNamedValueInfo(annotation) :
new RequestParamNamedValueInfo();
}
@@ -140,9 +141,9 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethod
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest webRequest) throws Exception {
Object arg;
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
MultipartHttpServletRequest multipartRequest =
MultipartHttpServletRequest multipartRequest =
WebUtils.getNativeRequest(servletRequest, MultipartHttpServletRequest.class);
if (MultipartFile.class.equals(parameter.getParameterType())) {
@@ -174,7 +175,7 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethod
}
}
}
return arg;
}
@@ -184,7 +185,7 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethod
throw new MultipartException("The current request is not a multipart request");
}
}
private boolean isMultipartFileCollection(MethodParameter parameter) {
Class<?> paramType = parameter.getParameterType();
if (Collection.class.equals(paramType) || List.class.isAssignableFrom(paramType)){
@@ -206,7 +207,7 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethod
private RequestParamNamedValueInfo() {
super("", false, ValueConstants.DEFAULT_NONE);
}
private RequestParamNamedValueInfo(RequestParam annotation) {
super(annotation.value(), annotation.required(), annotation.defaultValue());
}