Merge branch '3.1.x'

This commit is contained in:
Chris Beams
2012-01-25 23:17:39 +01:00
63 changed files with 1211 additions and 494 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 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.
@@ -24,6 +24,7 @@ package org.springframework.http;
* @author Arjen Poutsma
* @see HttpStatus.Series
* @see <a href="http://www.iana.org/assignments/http-status-codes">HTTP Status Code Registry</a>
* @see <a href="http://en.wikipedia.org/wiki/List_of_HTTP_status_codes">List of HTTP status codes - Wikipedia</a>
*/
public enum HttpStatus {
@@ -44,6 +45,12 @@ public enum HttpStatus {
* @see <a href="http://tools.ietf.org/html/rfc2518#section-10.1">WebDAV</a>
*/
PROCESSING(102, "Processing"),
/**
* {@code 103 Checkpoint}.
* @see <a href="http://code.google.com/p/gears/wiki/ResumableHttpRequestsProposal">A proposal for supporting
* resumable POST/PUT HTTP requests in HTTP/1.0</a>
*/
CHECKPOINT(103, "Checkpoint"),
// 2xx Success
@@ -140,6 +147,12 @@ public enum HttpStatus {
* @see <a href="http://tools.ietf.org/html/rfc2616#section-10.3.8">HTTP/1.1</a>
*/
TEMPORARY_REDIRECT(307, "Temporary Redirect"),
/**
* {@code 308 Resume Incomplete}.
* @see <a href="http://code.google.com/p/gears/wiki/ResumableHttpRequestsProposal">A proposal for supporting
* resumable POST/PUT HTTP requests in HTTP/1.0</a>
*/
RESUME_INCOMPLETE(308, "Resume Incomplete"),
// --- 4xx Client Error ---
@@ -187,7 +200,7 @@ public enum HttpStatus {
* {@code 408 Request Timeout}.
* @see <a href="http://tools.ietf.org/html/rfc2616#section-10.4.9">HTTP/1.1</a>
*/
REQUEST_TIMEOUT(408, "Request Time-out"),
REQUEST_TIMEOUT(408, "Request Timeout"),
/**
* {@code 409 Conflict}.
* @see <a href="http://tools.ietf.org/html/rfc2616#section-10.4.10">HTTP/1.1</a>
@@ -217,7 +230,7 @@ public enum HttpStatus {
* {@code 414 Request-URI Too Long}.
* @see <a href="http://tools.ietf.org/html/rfc2616#section-10.4.15">HTTP/1.1</a>
*/
REQUEST_URI_TOO_LONG(414, "Request-URI Too Large"),
REQUEST_URI_TOO_LONG(414, "Request-URI Too Long"),
/**
* {@code 415 Unsupported Media Type}.
* @see <a href="http://tools.ietf.org/html/rfc2616#section-10.4.16">HTTP/1.1</a>
@@ -233,6 +246,11 @@ public enum HttpStatus {
* @see <a href="http://tools.ietf.org/html/rfc2616#section-10.4.18">HTTP/1.1</a>
*/
EXPECTATION_FAILED(417, "Expectation Failed"),
/**
* {@code 418 I'm a teapot}.
* @see <a href="http://tools.ietf.org/html/rfc2324#section-2.3.2">HTCPCP/1.0</a>
*/
I_AM_A_TEAPOT(418, "I'm a teapot"),
/**
* {@code 419 Insufficient Space on Resource}.
* @see <a href="http://tools.ietf.org/html/draft-ietf-webdav-protocol-05#section-10.4">WebDAV Draft</a>
@@ -268,6 +286,24 @@ public enum HttpStatus {
* @see <a href="http://tools.ietf.org/html/rfc2817#section-6">Upgrading to TLS Within HTTP/1.1</a>
*/
UPGRADE_REQUIRED(426, "Upgrade Required"),
/**
* {@code 428 Precondition Required}.
* @see <a href="http://tools.ietf.org/html/draft-nottingham-http-new-status-02#section-3">Additional HTTP Status
* Codes</a>
*/
PRECONDITION_REQUIRED(428, "Precondition Required"),
/**
* {@code 429 Too Many Requests}.
* @see <a href="http://tools.ietf.org/html/draft-nottingham-http-new-status-02#section-4">Additional HTTP Status
* Codes</a>
*/
TOO_MANY_REQUESTS(429, "Too Many Requests"),
/**
* {@code 431 Request Header Fields Too Large}.
* @see <a href="http://tools.ietf.org/html/draft-nottingham-http-new-status-02#section-5">Additional HTTP Status
* Codes</a>
*/
REQUEST_HEADER_FIELDS_TOO_LARGE(431, "Request Header Fields Too Large"),
// --- 5xx Server Error ---
@@ -295,7 +331,7 @@ public enum HttpStatus {
* {@code 504 Gateway Timeout}.
* @see <a href="http://tools.ietf.org/html/rfc2616#section-10.5.5">HTTP/1.1</a>
*/
GATEWAY_TIMEOUT(504, "Gateway Time-out"),
GATEWAY_TIMEOUT(504, "Gateway Timeout"),
/**
* {@code 505 HTTP Version Not Supported}.
* @see <a href="http://tools.ietf.org/html/rfc2616#section-10.5.6">HTTP/1.1</a>
@@ -316,11 +352,22 @@ public enum HttpStatus {
* @see <a href="http://tools.ietf.org/html/draft-ietf-webdav-bind-27#section-7.2">WebDAV Binding Extensions</a>
*/
LOOP_DETECTED(508, "Loop Detected"),
/**
* {@code 509 Bandwidth Limit Exceeded}
*/
BANDWIDTH_LIMIT_EXCEEDED(509, "Bandwidth Limit Exceeded"),
/**
* {@code 510 Not Extended}
* @see <a href="http://tools.ietf.org/html/rfc2774#section-7">HTTP Extension Framework</a>
*/
NOT_EXTENDED(510, "Not Extended");
NOT_EXTENDED(510, "Not Extended"),
/**
* {@code 511 Network Authentication Required}.
* @see <a href="http://tools.ietf.org/html/draft-nottingham-http-new-status-02#section-6">Additional HTTP Status
* Codes</a>
*/
NETWORK_AUTHENTICATION_REQUIRED(511, "Network Authentication Required");
private final int value;

View File

@@ -331,7 +331,7 @@ public class MediaType implements Comparable<MediaType> {
String attribute = entry.getKey();
String value = entry.getValue();
checkParameters(attribute, value);
m.put(attribute, unquote(value));
m.put(attribute, value);
}
this.parameters = Collections.unmodifiableMap(m);
}
@@ -428,7 +428,7 @@ public class MediaType implements Comparable<MediaType> {
*/
public Charset getCharSet() {
String charSet = getParameter(PARAM_CHARSET);
return (charSet != null ? Charset.forName(charSet) : null);
return (charSet != null ? Charset.forName(unquote(charSet)) : null);
}
/**
@@ -438,7 +438,7 @@ public class MediaType implements Comparable<MediaType> {
*/
public double getQualityValue() {
String qualityFactory = getParameter(PARAM_QUALITY_FACTOR);
return (qualityFactory != null ? Double.parseDouble(qualityFactory) : 1D);
return (qualityFactory != null ? Double.parseDouble(unquote(qualityFactory)) : 1D);
}
/**

View File

@@ -0,0 +1,35 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.http.client;
import java.io.IOException;
import org.springframework.http.HttpStatus;
/**
* Abstract base for {@link ClientHttpResponse}.
*
* @author Arjen Poutsma
* @since 3.1.1
*/
public abstract class AbstractClientHttpResponse implements ClientHttpResponse {
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.valueOf(getRawStatusCode());
}
}

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.
@@ -47,6 +47,10 @@ final class BufferingClientHttpResponseWrapper implements ClientHttpResponse {
return this.response.getStatusCode();
}
public int getRawStatusCode() throws IOException {
return this.response.getRawStatusCode();
}
public String getStatusText() throws IOException {
return this.response.getStatusText();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 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.
@@ -39,6 +39,13 @@ public interface ClientHttpResponse extends HttpInputMessage {
*/
HttpStatus getStatusCode() throws IOException;
/**
* Return the HTTP status code of the response as integer
* @return the HTTP status as an integer
* @throws IOException in case of I/O errors
*/
int getRawStatusCode() throws IOException;
/**
* Return the HTTP status text of the response.
* @return the HTTP status text

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.
@@ -23,7 +23,6 @@ import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpMethod;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
/**
* {@link org.springframework.http.client.ClientHttpResponse} implementation that uses
@@ -37,7 +36,7 @@ import org.springframework.http.HttpStatus;
* @deprecated In favor of {@link HttpComponentsClientHttpResponse}
*/
@Deprecated
final class CommonsClientHttpResponse implements ClientHttpResponse {
final class CommonsClientHttpResponse extends AbstractClientHttpResponse {
private final HttpMethod httpMethod;
@@ -49,8 +48,8 @@ final class CommonsClientHttpResponse implements ClientHttpResponse {
}
public HttpStatus getStatusCode() {
return HttpStatus.valueOf(this.httpMethod.getStatusCode());
public int getRawStatusCode() {
return this.httpMethod.getStatusCode();
}
public String getStatusText() {

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.
@@ -25,7 +25,6 @@ import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
/**
* {@link org.springframework.http.client.ClientHttpResponse} implementation that uses
@@ -38,20 +37,20 @@ import org.springframework.http.HttpStatus;
* @since 3.1
* @see HttpComponentsClientHttpRequest#execute()
*/
final class HttpComponentsClientHttpResponse implements ClientHttpResponse {
final class HttpComponentsClientHttpResponse extends AbstractClientHttpResponse {
private final HttpResponse httpResponse;
private HttpHeaders headers;
public HttpComponentsClientHttpResponse(HttpResponse httpResponse) {
HttpComponentsClientHttpResponse(HttpResponse httpResponse) {
this.httpResponse = httpResponse;
}
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.valueOf(this.httpResponse.getStatusLine().getStatusCode());
public int getRawStatusCode() throws IOException {
return this.httpResponse.getStatusLine().getStatusCode();
}
public String getStatusText() throws IOException {

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.
@@ -21,7 +21,6 @@ import java.io.InputStream;
import java.net.HttpURLConnection;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;
/**
@@ -32,7 +31,7 @@ import org.springframework.util.StringUtils;
* @author Arjen Poutsma
* @since 3.0
*/
final class SimpleClientHttpResponse implements ClientHttpResponse {
final class SimpleClientHttpResponse extends AbstractClientHttpResponse {
private final HttpURLConnection connection;
@@ -44,8 +43,8 @@ final class SimpleClientHttpResponse implements ClientHttpResponse {
}
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.valueOf(this.connection.getResponseCode());
public int getRawStatusCode() throws IOException {
return this.connection.getResponseCode();
}
public String getStatusText() throws IOException {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 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.
@@ -407,7 +407,13 @@ public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory
*/
protected Object getPortStub(Service service, QName portQName) {
if (this.webServiceFeatures != null) {
return new FeaturePortProvider().getPortStub(service, portQName, this.webServiceFeatures);
try {
return new FeaturePortProvider().getPortStub(service, portQName, this.webServiceFeatures);
}
catch (LinkageError ex) {
throw new IllegalStateException(
"Specifying the 'webServiceFeatures' property requires JAX-WS 2.1 or higher at runtime", ex);
}
}
else {
return (portQName != null ? service.getPort(portQName, getServiceInterface()) :
@@ -527,6 +533,7 @@ public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory
}
}
/**
* Inner class in order to avoid a hard-coded JAX-WS 2.1 dependency.
* JAX-WS 2.0, as used in Java EE 5, didn't have WebServiceFeatures yet...

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.
@@ -35,8 +35,8 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
/**
* 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.
* 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.
* <p>Subclasses define how to do the following:
* <ul>
* <li>Obtain named value information for a method parameter
@@ -44,11 +44,11 @@ import org.springframework.web.method.support.ModelAndViewContainer;
* <li>Handle missing argument values when argument values are required
* <li>Optionally handle a resolved value
* </ul>
* <p>A default value string can contain ${...} placeholders and Spring Expression Language #{...} expressions.
* <p>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.
* <p>A {@link WebDataBinder} is created to apply type conversion to the resolved argument value if it doesn't
* <p>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
@@ -63,7 +63,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
new ConcurrentHashMap<MethodParameter, NamedValueInfo>();
/**
* @param beanFactory a bean factory to use for resolving ${...} placeholder and #{...} SpEL expressions
* @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) {
@@ -71,10 +71,11 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
this.expressionContext = (beanFactory != null) ? new BeanExpressionContext(beanFactory, new RequestScope()) : null;
}
public final Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
public final Object resolveArgument(
MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
throws Exception {
Class<?> paramType = parameter.getParameterType();
NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
@@ -95,7 +96,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
arg = binder.convertIfNecessary(arg, paramType, parameter);
}
handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);
return arg;
@@ -115,9 +116,9 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
}
/**
* Create the {@link NamedValueInfo} object for the given method parameter. Implementations typically
* 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
*/
@@ -136,7 +137,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
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
@@ -165,7 +166,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
}
/**
* Invoked when a named value is required, but {@link #resolveName(String, MethodParameter, NativeWebRequest)}
* 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
@@ -219,4 +220,4 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
this.defaultValue = defaultValue;
}
}
}
}

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.
@@ -28,16 +28,16 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
/**
* An abstract base class adapting a {@link WebArgumentResolver} to the
* {@link HandlerMethodArgumentResolver} contract.
*
* An abstract base class adapting a {@link WebArgumentResolver} to the
* {@link HandlerMethodArgumentResolver} contract.
*
* <p><strong>Note:</strong> This class is provided for backwards compatibility.
* However it is recommended to re-write a {@code WebArgumentResolver} as
* {@code HandlerMethodArgumentResolver}. Since {@link #supportsParameter}
* can only be implemented by actually resolving the value and then checking
* the result is not {@code WebArgumentResolver#UNRESOLVED} any exceptions
* raised must be absorbed and ignored since it's not clear whether the adapter
* doesn't support the parameter or whether it failed for an internal reason.
* However it is recommended to re-write a {@code WebArgumentResolver} as
* {@code HandlerMethodArgumentResolver}. Since {@link #supportsParameter}
* can only be implemented by actually resolving the value and then checking
* the result is not {@code WebArgumentResolver#UNRESOLVED} any exceptions
* raised must be absorbed and ignored since it's not clear whether the adapter
* doesn't support the parameter or whether it failed for an internal reason.
* The {@code HandlerMethodArgumentResolver} contract also provides access to
* model attributes and to {@code WebDataBinderFactory} (for type conversion).
*
@@ -60,7 +60,7 @@ public abstract class AbstractWebArgumentResolverAdapter implements HandlerMetho
}
/**
* Actually resolve the value and check the resolved value is not
* Actually resolve the value and check the resolved value is not
* {@link WebArgumentResolver#UNRESOLVED} absorbing _any_ exceptions.
*/
public boolean supportsParameter(MethodParameter parameter) {
@@ -88,21 +88,22 @@ public abstract class AbstractWebArgumentResolverAdapter implements HandlerMetho
/**
* Delegate to the {@link WebArgumentResolver} instance.
* @exception IllegalStateException if the resolved value is not assignable
* @exception IllegalStateException if the resolved value is not assignable
* to the method parameter.
*/
public Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
public Object resolveArgument(
MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
throws Exception {
Class<?> paramType = parameter.getParameterType();
Object result = this.adaptee.resolveArgument(parameter, webRequest);
if (result == WebArgumentResolver.UNRESOLVED || !ClassUtils.isAssignableValue(paramType, result)) {
throw new IllegalStateException(
"Standard argument type [" + paramType.getName() + "] in method " + parameter.getMethod() +
"Standard argument type [" + paramType.getName() + "] in method " + parameter.getMethod() +
"resolved to incompatible value of type [" + (result != null ? result.getClass() : null) +
"]. Consider declaring the argument type in a less specific fashion.");
}
return result;
}
}
}

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.
@@ -29,12 +29,12 @@ import org.springframework.web.method.support.ModelAndViewContainer;
/**
* Resolves {@link Errors} method arguments.
*
*
* <p>An {@code Errors} method argument is expected to appear immediately after
* the model attribute in the method signature. It is resolved by expecting the
* last two attributes added to the model to be the model attribute and its
* {@link BindingResult}.
*
* {@link BindingResult}.
*
* @author Rossen Stoyanchev
* @since 3.1
*/
@@ -45,10 +45,11 @@ public class ErrorsMethodArgumentResolver implements HandlerMethodArgumentResolv
return Errors.class.isAssignableFrom(paramType);
}
public Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
public Object resolveArgument(
MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
throws Exception {
ModelMap model = mavContainer.getModel();
if (model.size() > 0) {
int lastIndex = model.size()-1;
@@ -63,4 +64,4 @@ public class ErrorsMethodArgumentResolver implements HandlerMethodArgumentResolv
"argument in the controller method signature: " + parameter.getMethod());
}
}
}

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.
@@ -27,12 +27,12 @@ import org.springframework.web.method.support.ModelAndViewContainer;
/**
* Resolves {@link Map} method arguments and handles {@link Map} return values.
*
* <p>A Map return value can be interpreted in more than one ways depending
* on the presence of annotations like {@code @ModelAttribute} or
*
* <p>A Map return value can be interpreted in more than one ways depending
* on the presence of annotations like {@code @ModelAttribute} or
* {@code @ResponseBody}. Therefore this handler should be configured after
* the handlers that support these annotations.
*
*
* @author Rossen Stoyanchev
* @since 3.1
*/
@@ -42,10 +42,11 @@ public class MapMethodProcessor implements HandlerMethodArgumentResolver, Handle
return Map.class.isAssignableFrom(parameter.getParameterType());
}
public Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
public Object resolveArgument(
MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
throws Exception {
return mavContainer.getModel();
}
@@ -54,10 +55,11 @@ public class MapMethodProcessor implements HandlerMethodArgumentResolver, Handle
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public void handleReturnValue(Object returnValue,
MethodParameter returnType,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest) throws Exception {
public void handleReturnValue(
Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws Exception {
if (returnValue == null) {
return;
}
@@ -66,8 +68,8 @@ public class MapMethodProcessor implements HandlerMethodArgumentResolver, Handle
}
else {
// should not happen
throw new UnsupportedOperationException("Unexpected return type: " +
throw new UnsupportedOperationException("Unexpected return type: " +
returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
}
}
}
}

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.
@@ -39,15 +39,15 @@ import org.springframework.web.method.support.ModelAndViewContainer;
/**
* Resolves method arguments annotated with {@code @ModelAttribute} and handles
* return values from methods annotated with {@code @ModelAttribute}.
*
* <p>Model attributes are obtained from the model or if not found possibly
* created with a default constructor if it is available. Once created, the
* attributed is populated with request data via data binding and also
* validation may be applied if the argument is annotated with
*
* <p>Model attributes are obtained from the model or if not found possibly
* created with a default constructor if it is available. Once created, the
* attributed is populated with request data via data binding and also
* validation may be applied if the argument is annotated with
* {@code @javax.validation.Valid}.
*
* <p>When this handler is created with {@code annotationNotRequired=true},
* any non-simple type argument and return value is regarded as a model
* <p>When this handler is created with {@code annotationNotRequired=true},
* any non-simple type argument and return value is regarded as a model
* attribute with or without the presence of an {@code @ModelAttribute}.
*
* @author Rossen Stoyanchev
@@ -58,10 +58,10 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
protected Log logger = LogFactory.getLog(this.getClass());
private final boolean annotationNotRequired;
/**
* @param annotationNotRequired if "true", non-simple method arguments and
* return values are considered model attributes with or without a
* return values are considered model attributes with or without a
* {@code @ModelAttribute} annotation.
*/
public ModelAttributeMethodProcessor(boolean annotationNotRequired) {
@@ -85,18 +85,19 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
}
/**
* Resolve the argument from the model or if not found instantiate it with
* its default if it is available. The model attribute is then populated
* Resolve the argument from the model or if not found instantiate it with
* its default if it is available. The model attribute is then populated
* with request values via data binding and optionally validated
* if {@code @java.validation.Valid} is present on the argument.
* @throws BindException if data binding and validation result in an error
* and the next method parameter is not of type {@link Errors}.
* @throws Exception if WebDataBinder initialization fails.
*/
public final Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest request,
WebDataBinderFactory binderFactory) throws Exception {
public final Object resolveArgument(
MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest request, WebDataBinderFactory binderFactory)
throws Exception {
String name = ModelFactory.getNameForParameter(parameter);
Object target = (mavContainer.containsAttribute(name)) ?
mavContainer.getModel().get(name) : createAttribute(name, parameter, binderFactory, request);
@@ -130,7 +131,7 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
return BeanUtils.instantiateClass(parameter.getParameterType());
}
/**
* Extension point to bind the request to the target object.
* @param binder the data binder instance to use for the binding
@@ -158,7 +159,7 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
/**
* Whether to raise a {@link BindException} on bind or validation errors.
* The default implementation returns {@code true} if the next method
* The default implementation returns {@code true} if the next method
* argument is not of type {@link Errors}.
* @param binder the data binder used to perform data binding
* @param parameter the method argument
@@ -167,12 +168,12 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
int i = parameter.getParameterIndex();
Class<?>[] paramTypes = parameter.getMethod().getParameterTypes();
boolean hasBindingResult = (paramTypes.length > (i + 1) && Errors.class.isAssignableFrom(paramTypes[i + 1]));
return !hasBindingResult;
}
/**
* Return {@code true} if there is a method-level {@code @ModelAttribute}
* Return {@code true} if there is a method-level {@code @ModelAttribute}
* or if it is a non-simple type when {@code annotationNotRequired=true}.
*/
public boolean supportsReturnType(MethodParameter returnType) {
@@ -190,13 +191,14 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
/**
* Add non-null return values to the {@link ModelAndViewContainer}.
*/
public void handleReturnValue(Object returnValue,
MethodParameter returnType,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest) throws Exception {
public void handleReturnValue(
Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws Exception {
if (returnValue != null) {
String name = ModelFactory.getNameForReturnValue(returnValue, returnType);
mavContainer.addAttribute(name, returnValue);
}
}
}
}

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.
@@ -25,13 +25,13 @@ import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;
/**
* Resolves {@link Model} arguments and handles {@link Model} return values.
*
* <p>A {@link Model} return type has a set purpose. Therefore this handler
* should be configured ahead of handlers that support any return value type
* Resolves {@link Model} arguments and handles {@link Model} return values.
*
* <p>A {@link Model} return type has a set purpose. Therefore this handler
* should be configured ahead of handlers that support any return value type
* annotated with {@code @ModelAttribute} or {@code @ResponseBody} to ensure
* they don't take over.
*
*
* @author Rossen Stoyanchev
* @since 3.1
*/
@@ -41,10 +41,11 @@ public class ModelMethodProcessor implements HandlerMethodArgumentResolver, Hand
return Model.class.isAssignableFrom(parameter.getParameterType());
}
public Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
public Object resolveArgument(
MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
throws Exception {
return mavContainer.getModel();
}
@@ -52,10 +53,11 @@ public class ModelMethodProcessor implements HandlerMethodArgumentResolver, Hand
return Model.class.isAssignableFrom(returnType.getParameterType());
}
public void handleReturnValue(Object returnValue,
MethodParameter returnType,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest) throws Exception {
public void handleReturnValue(
Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws Exception {
if (returnValue == null) {
return;
}
@@ -64,8 +66,8 @@ public class ModelMethodProcessor implements HandlerMethodArgumentResolver, Hand
}
else {
// should not happen
throw new UnsupportedOperationException("Unexpected return type: " +
throw new UnsupportedOperationException("Unexpected return type: " +
returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
}
}
}
}

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.
@@ -31,13 +31,13 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
/**
* Resolves {@link Map} method arguments annotated with {@code @RequestHeader}.
* For individual header values annotated with {@code @RequestHeader} see
* Resolves {@link Map} method arguments annotated with {@code @RequestHeader}.
* For individual header values annotated with {@code @RequestHeader} see
* {@link RequestHeaderMethodArgumentResolver} instead.
*
* <p>The created {@link Map} contains all request header name/value pairs.
*
* <p>The created {@link Map} contains all request header name/value pairs.
* The method parameter type may be a {@link MultiValueMap} to receive all
* values for a header, not only the first one.
* values for a header, not only the first one.
*
* @author Arjen Poutsma
* @author Rossen Stoyanchev
@@ -50,10 +50,11 @@ public class RequestHeaderMapMethodArgumentResolver implements HandlerMethodArgu
&& Map.class.isAssignableFrom(parameter.getParameterType());
}
public Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
public Object resolveArgument(
MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
throws Exception {
Class<?> paramType = parameter.getParameterType();
if (MultiValueMap.class.isAssignableFrom(paramType)) {
@@ -82,4 +83,4 @@ public class RequestHeaderMapMethodArgumentResolver implements HandlerMethodArgu
return result;
}
}
}
}

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.
@@ -30,12 +30,12 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
/**
* 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}
* 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.
*
* <p>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
*
* <p>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
@@ -55,10 +55,11 @@ public class RequestParamMapMethodArgumentResolver implements HandlerMethodArgum
return false;
}
public Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
public Object resolveArgument(
MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
throws Exception {
Class<?> paramType = parameter.getParameterType();
Map<String, String[]> parameterMap = webRequest.getParameterMap();
@@ -81,4 +82,4 @@ public class RequestParamMapMethodArgumentResolver implements HandlerMethodArgum
return result;
}
}
}
}

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.
@@ -24,7 +24,7 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
/**
* Resolves a {@link SessionStatus} argument by obtaining it from
* Resolves a {@link SessionStatus} argument by obtaining it from
* the {@link ModelAndViewContainer}.
*
* @author Rossen Stoyanchev
@@ -36,10 +36,11 @@ public class SessionStatusMethodArgumentResolver implements HandlerMethodArgumen
return SessionStatus.class.equals(parameter.getParameterType());
}
public Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
public Object resolveArgument(
MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
throws Exception {
return mavContainer.getSessionStatus();
}

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.
@@ -31,8 +31,8 @@ import org.springframework.web.context.request.NativeWebRequest;
/**
* Resolves method parameters by delegating to a list of registered {@link HandlerMethodArgumentResolver}s.
* Previously resolved method parameters are cached for faster lookups.
*
* Previously resolved method parameters are cached for faster lookups.
*
* @author Rossen Stoyanchev
* @since 3.1
*/
@@ -40,12 +40,12 @@ public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgu
protected final Log logger = LogFactory.getLog(getClass());
private final List<HandlerMethodArgumentResolver> argumentResolvers =
private final List<HandlerMethodArgumentResolver> argumentResolvers =
new ArrayList<HandlerMethodArgumentResolver>();
private final Map<MethodParameter, HandlerMethodArgumentResolver> argumentResolverCache =
new ConcurrentHashMap<MethodParameter, HandlerMethodArgumentResolver>();
/**
* Return a read-only list with the contained resolvers, or an empty list.
*/
@@ -54,7 +54,7 @@ public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgu
}
/**
* Whether the given {@linkplain MethodParameter method parameter} is supported by any registered
* Whether the given {@linkplain MethodParameter method parameter} is supported by any registered
* {@link HandlerMethodArgumentResolver}.
*/
public boolean supportsParameter(MethodParameter parameter) {
@@ -65,10 +65,11 @@ public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgu
* Iterate over registered {@link HandlerMethodArgumentResolver}s and invoke the one that supports it.
* @exception IllegalStateException if no suitable {@link HandlerMethodArgumentResolver} is found.
*/
public Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
public Object resolveArgument(
MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
throws Exception {
HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
Assert.notNull(resolver, "Unknown parameter type [" + parameter.getParameterType().getName() + "]");
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
@@ -94,7 +95,7 @@ public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgu
}
return result;
}
/**
* Add the given {@link HandlerMethodArgumentResolver}.
*/
@@ -116,4 +117,4 @@ public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgu
return this;
}
}
}

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.
@@ -29,17 +29,17 @@ import org.springframework.util.Assert;
import org.springframework.web.context.request.NativeWebRequest;
/**
* Handles method return values by delegating to a list of registered {@link HandlerMethodReturnValueHandler}s.
* Previously resolved return types are cached for faster lookups.
*
* Handles method return values by delegating to a list of registered {@link HandlerMethodReturnValueHandler}s.
* Previously resolved return types are cached for faster lookups.
*
* @author Rossen Stoyanchev
* @since 3.1
*/
public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler {
protected final Log logger = LogFactory.getLog(getClass());
private final List<HandlerMethodReturnValueHandler> returnValueHandlers =
private final List<HandlerMethodReturnValueHandler> returnValueHandlers =
new ArrayList<HandlerMethodReturnValueHandler>();
private final Map<MethodParameter, HandlerMethodReturnValueHandler> returnValueHandlerCache =
@@ -53,7 +53,7 @@ public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodRe
}
/**
* Whether the given {@linkplain MethodParameter method return type} is supported by any registered
* Whether the given {@linkplain MethodParameter method return type} is supported by any registered
* {@link HandlerMethodReturnValueHandler}.
*/
public boolean supportsReturnType(MethodParameter returnType) {
@@ -64,10 +64,11 @@ public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodRe
* Iterate over registered {@link HandlerMethodReturnValueHandler}s and invoke the one that supports it.
* @exception IllegalStateException if no suitable {@link HandlerMethodReturnValueHandler} is found.
*/
public void handleReturnValue(Object returnValue,
MethodParameter returnType,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest) throws Exception {
public void handleReturnValue(
Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws Exception {
HandlerMethodReturnValueHandler handler = getReturnValueHandler(returnType);
Assert.notNull(handler, "Unknown return value type [" + returnType.getParameterType().getName() + "]");
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
@@ -92,8 +93,8 @@ public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodRe
}
}
return result;
}
}
/**
* Add the given {@link HandlerMethodReturnValueHandler}.
*/
@@ -115,4 +116,4 @@ public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodRe
return this;
}
}
}

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.
@@ -32,16 +32,16 @@ import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.HandlerMethod;
/**
* Provides a method for invoking the handler method for a given request after resolving its method argument
* Provides a method for invoking the handler method for a given request after resolving its method argument
* values through registered {@link HandlerMethodArgumentResolver}s.
*
* <p>Argument resolution often requires a {@link WebDataBinder} for data binding or for type conversion.
*
* <p>Argument resolution often requires a {@link WebDataBinder} for data binding or for type conversion.
* Use the {@link #setDataBinderFactory(WebDataBinderFactory)} property to supply a binder factory to pass to
* argument resolvers.
*
* <p>Use {@link #setHandlerMethodArgumentResolvers(HandlerMethodArgumentResolverComposite)} to customize
* argument resolvers.
*
* <p>Use {@link #setHandlerMethodArgumentResolvers(HandlerMethodArgumentResolverComposite)} to customize
* the list of argument resolvers.
*
*
* @author Rossen Stoyanchev
* @since 3.1
*/
@@ -99,20 +99,20 @@ public class InvocableHandlerMethod extends HandlerMethod {
}
/**
* Invoke the method after resolving its argument values in the context of the given request. <p>Argument
* values are commonly resolved through {@link HandlerMethodArgumentResolver}s. The {@code provideArgs}
* parameter however may supply argument values to be used directly, i.e. without argument resolution.
* Examples of provided argument values include a {@link WebDataBinder}, a {@link SessionStatus}, or
* Invoke the method after resolving its argument values in the context of the given request. <p>Argument
* values are commonly resolved through {@link HandlerMethodArgumentResolver}s. The {@code provideArgs}
* parameter however may supply argument values to be used directly, i.e. without argument resolution.
* Examples of provided argument values include a {@link WebDataBinder}, a {@link SessionStatus}, or
* a thrown exception instance. Provided argument values are checked before argument resolvers.
*
*
* @param request the current request
* @param mavContainer the {@link ModelAndViewContainer} for the current request
* @param providedArgs argument values to try to use without view resolution
* @return the raw value returned by the invoked method
* @exception Exception raised if no suitable argument resolver can be found, or the method raised an exception
* @exception Exception raised if no suitable argument resolver can be found, or the method raised an exception
*/
public final Object invokeForRequest(NativeWebRequest request,
ModelAndViewContainer mavContainer,
public final Object invokeForRequest(NativeWebRequest request,
ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
@@ -135,9 +135,10 @@ public class InvocableHandlerMethod extends HandlerMethod {
/**
* Get the method argument values for the current request.
*/
private Object[] getMethodArgumentValues(NativeWebRequest request,
ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
private Object[] getMethodArgumentValues(
NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
MethodParameter[] parameters = getMethodParameters();
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
@@ -187,7 +188,7 @@ public class InvocableHandlerMethod extends HandlerMethod {
sb.append("Method [").append(getBridgedMethod().toGenericString()).append("]\n");
return sb.toString();
}
/**
* Attempt to resolve a method parameter from the list of provided argument values.
*/
@@ -202,7 +203,7 @@ public class InvocableHandlerMethod extends HandlerMethod {
}
return null;
}
/**
* Invoke the handler method with the given argument values.
*/
@@ -215,7 +216,7 @@ public class InvocableHandlerMethod extends HandlerMethod {
String msg = getInvocationErrorMessage(e.getMessage(), args);
throw new IllegalArgumentException(msg, e);
}
catch (InvocationTargetException e) {
catch (InvocationTargetException e) {
// Unwrap for HandlerExceptionResolvers ...
Throwable targetException = e.getTargetException();
if (targetException instanceof RuntimeException) {
@@ -233,7 +234,7 @@ public class InvocableHandlerMethod extends HandlerMethod {
}
}
}
private String getInvocationErrorMessage(String message, Object[] resolvedArgs) {
StringBuilder sb = new StringBuilder(getDetailedErrorMessage(message));
sb.append("Resolved arguments: \n");
@@ -250,4 +251,4 @@ public class InvocableHandlerMethod extends HandlerMethod {
return sb.toString();
}
}
}

View File

@@ -18,6 +18,8 @@ package org.springframework.web.util;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.springframework.util.Assert;
@@ -38,38 +40,107 @@ import org.springframework.util.Assert;
*/
public abstract class UriUtils {
private static final String SCHEME_PATTERN = "([^:/?#]+):";
private static final String HTTP_PATTERN = "(http|https):";
private static final String USERINFO_PATTERN = "([^@/]*)";
private static final String HOST_PATTERN = "([^/?#:]*)";
private static final String PORT_PATTERN = "(\\d*)";
private static final String PATH_PATTERN = "([^?#]*)";
private static final String QUERY_PATTERN = "([^#]*)";
private static final String LAST_PATTERN = "(.*)";
// Regex patterns that matches URIs. See RFC 3986, appendix B
private static final Pattern URI_PATTERN = Pattern.compile(
"^(" + SCHEME_PATTERN + ")?" + "(//(" + USERINFO_PATTERN + "@)?" + HOST_PATTERN + "(:" + PORT_PATTERN +
")?" + ")?" + PATH_PATTERN + "(\\?" + QUERY_PATTERN + ")?" + "(#" + LAST_PATTERN + ")?");
private static final Pattern HTTP_URL_PATTERN = Pattern.compile(
"^" + HTTP_PATTERN + "(//(" + USERINFO_PATTERN + "@)?" + HOST_PATTERN + "(:" + PORT_PATTERN + ")?" + ")?" +
PATH_PATTERN + "(\\?" + LAST_PATTERN + ")?");
// encoding
/**
* Encodes the given source URI into an encoded String. All various URI components are
* encoded according to their respective valid character sets.
* <p><strong>Note</strong> that this method does not attempt to encode "=" and "&"
* characters in query parameter names and query parameter values because they cannot
* be parsed in a reliable way. Instead use:
* <pre>
* UriComponents uriComponents = UriComponentsBuilder.fromUri("/path?name={value}").buildAndExpand("a=b");
* String encodedUri = uriComponents.encode().toUriString();
* </pre>
* @param uri the URI to be encoded
* @param encoding the character encoding to encode to
* @return the encoded URI
* @throws IllegalArgumentException when the given uri parameter is not a valid URI
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
* @deprecated in favor of {@link UriComponentsBuilder}; see note about query param encoding
*/
public static String encodeUri(String uri, String encoding) throws UnsupportedEncodingException {
UriComponents uriComponents = UriComponentsBuilder.fromUriString(uri).build();
UriComponents encoded = uriComponents.encode(encoding);
return encoded.toUriString();
}
Assert.notNull(uri, "'uri' must not be null");
Assert.hasLength(encoding, "'encoding' must not be empty");
Matcher m = URI_PATTERN.matcher(uri);
if (m.matches()) {
String scheme = m.group(2);
String authority = m.group(3);
String userinfo = m.group(5);
String host = m.group(6);
String port = m.group(8);
String path = m.group(9);
String query = m.group(11);
String fragment = m.group(13);
return encodeUriComponents(scheme, authority, userinfo, host, port, path, query, fragment, encoding);
}
else {
throw new IllegalArgumentException("[" + uri + "] is not a valid URI");
}
}
/**
* Encodes the given HTTP URI into an encoded String. All various URI components are
* encoded according to their respective valid character sets.
* <p><strong>Note</strong> that this method does not support fragments ({@code #}),
* as these are not supposed to be sent to the server, but retained by the client.
* <p><strong>Note</strong> that this method does not attempt to encode "=" and "&"
* characters in query parameter names and query parameter values because they cannot
* be parsed in a reliable way. Instead use:
* <pre>
* UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl("/path?name={value}").buildAndExpand("a=b");
* String encodedUri = uriComponents.encode().toUriString();
* </pre>
* @param httpUrl the HTTP URL to be encoded
* @param encoding the character encoding to encode to
* @return the encoded URL
* @throws IllegalArgumentException when the given uri parameter is not a valid URI
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
* @deprecated in favor of {@link UriComponentsBuilder}; see note about query param encoding
*/
public static String encodeHttpUrl(String httpUrl, String encoding) throws UnsupportedEncodingException {
UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(httpUrl).build();
UriComponents encoded = uriComponents.encode(encoding);
return encoded.toUriString();
Assert.notNull(httpUrl, "'httpUrl' must not be null");
Assert.hasLength(encoding, "'encoding' must not be empty");
Matcher m = HTTP_URL_PATTERN.matcher(httpUrl);
if (m.matches()) {
String scheme = m.group(1);
String authority = m.group(2);
String userinfo = m.group(4);
String host = m.group(5);
String portString = m.group(7);
String path = m.group(8);
String query = m.group(10);
return encodeUriComponents(scheme, authority, userinfo, host, portString, path, query, null, encoding);
}
else {
throw new IllegalArgumentException("[" + httpUrl + "] is not a valid HTTP URL");
}
}
/**
@@ -87,20 +158,48 @@ public abstract class UriUtils {
* @return the encoded URI
* @throws IllegalArgumentException when the given uri parameter is not a valid URI
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
* @deprecated in favor of {@link UriComponentsBuilder}
*/
public static String encodeUriComponents(String scheme, String authority, String userInfo,
String host, String port, String path, String query, String fragment, String encoding)
throws UnsupportedEncodingException {
int portAsInt = (port != null ? Integer.parseInt(port) : -1);
Assert.hasLength(encoding, "'encoding' must not be empty");
StringBuilder sb = new StringBuilder();
UriComponentsBuilder builder = UriComponentsBuilder.newInstance();
builder.scheme(scheme).userInfo(userInfo).host(host).port(portAsInt);
builder.path(path).query(query).fragment(fragment);
if (scheme != null) {
sb.append(encodeScheme(scheme, encoding));
sb.append(':');
}
UriComponents encoded = builder.build().encode(encoding);
if (authority != null) {
sb.append("//");
if (userInfo != null) {
sb.append(encodeUserInfo(userInfo, encoding));
sb.append('@');
}
if (host != null) {
sb.append(encodeHost(host, encoding));
}
if (port != null) {
sb.append(':');
sb.append(encodePort(port, encoding));
}
}
return encoded.toUriString();
sb.append(encodePath(path, encoding));
if (query != null) {
sb.append('?');
sb.append(encodeQuery(query, encoding));
}
if (fragment != null) {
sb.append('#');
sb.append(encodeFragment(fragment, encoding));
}
return sb.toString();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 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.
@@ -16,38 +16,110 @@
package org.springframework.http;
import static org.junit.Assert.*;
import java.util.LinkedHashMap;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
/** @author Arjen Poutsma */
public class HttpStatusTests {
private int[] registryValues =
new int[]{100, 101, 102, 200, 201, 202, 203, 204, 205, 206, 207, 208, 226, 300, 301, 302, 303, 304, 305,
307, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 422,
423, 424, 426, 500, 501, 502, 503, 504, 505, 506, 507, 508, 510,};
private Map<Integer, String> statusCodes = new LinkedHashMap<Integer, String>();
private String[] registryDescriptions =
new String[]{"CONTINUE", "SWITCHING_PROTOCOLS", "PROCESSING", "OK", "CREATED", "ACCEPTED",
"NON_AUTHORITATIVE_INFORMATION", "NO_CONTENT", "RESET_CONTENT", "PARTIAL_CONTENT", "MULTI_STATUS",
"ALREADY_REPORTED", "IM_USED", "MULTIPLE_CHOICES", "MOVED_PERMANENTLY", "FOUND", "SEE_OTHER",
"NOT_MODIFIED", "USE_PROXY", "TEMPORARY_REDIRECT", "BAD_REQUEST", "UNAUTHORIZED",
"PAYMENT_REQUIRED", "FORBIDDEN", "NOT_FOUND", "METHOD_NOT_ALLOWED", "NOT_ACCEPTABLE",
"PROXY_AUTHENTICATION_REQUIRED", "REQUEST_TIMEOUT", "CONFLICT", "GONE", "LENGTH_REQUIRED",
"PRECONDITION_FAILED", "REQUEST_ENTITY_TOO_LARGE", "REQUEST_URI_TOO_LONG", "UNSUPPORTED_MEDIA_TYPE",
"REQUESTED_RANGE_NOT_SATISFIABLE", "EXPECTATION_FAILED", "UNPROCESSABLE_ENTITY", "LOCKED",
"FAILED_DEPENDENCY", "UPGRADE_REQUIRED", "INTERNAL_SERVER_ERROR", "NOT_IMPLEMENTED", "BAD_GATEWAY",
"SERVICE_UNAVAILABLE", "GATEWAY_TIMEOUT", "HTTP_VERSION_NOT_SUPPORTED", "VARIANT_ALSO_NEGOTIATES",
"INSUFFICIENT_STORAGE", "LOOP_DETECTED", "NOT_EXTENDED",};
@Before
public void createStatusCodes() {
statusCodes.put(100, "CONTINUE");
statusCodes.put(101, "SWITCHING_PROTOCOLS");
statusCodes.put(102, "PROCESSING");
statusCodes.put(103, "CHECKPOINT");
@Test
public void registryValues() {
for (int i = 0; i < registryValues.length; i++) {
HttpStatus status = HttpStatus.valueOf(registryValues[i]);
assertEquals("Invalid value", registryValues[i], status.value());
assertEquals("Invalid descripion", registryDescriptions[i], status.name());
}
statusCodes.put(200, "OK");
statusCodes.put(201, "CREATED");
statusCodes.put(202, "ACCEPTED");
statusCodes.put(203, "NON_AUTHORITATIVE_INFORMATION");
statusCodes.put(204, "NO_CONTENT");
statusCodes.put(205, "RESET_CONTENT");
statusCodes.put(206, "PARTIAL_CONTENT");
statusCodes.put(207, "MULTI_STATUS");
statusCodes.put(208, "ALREADY_REPORTED");
statusCodes.put(226, "IM_USED");
statusCodes.put(300, "MULTIPLE_CHOICES");
statusCodes.put(301, "MOVED_PERMANENTLY");
statusCodes.put(302, "FOUND");
statusCodes.put(303, "SEE_OTHER");
statusCodes.put(304, "NOT_MODIFIED");
statusCodes.put(305, "USE_PROXY");
statusCodes.put(307, "TEMPORARY_REDIRECT");
statusCodes.put(308, "RESUME_INCOMPLETE");
statusCodes.put(400, "BAD_REQUEST");
statusCodes.put(401, "UNAUTHORIZED");
statusCodes.put(402, "PAYMENT_REQUIRED");
statusCodes.put(403, "FORBIDDEN");
statusCodes.put(404, "NOT_FOUND");
statusCodes.put(405, "METHOD_NOT_ALLOWED");
statusCodes.put(406, "NOT_ACCEPTABLE");
statusCodes.put(407, "PROXY_AUTHENTICATION_REQUIRED");
statusCodes.put(408, "REQUEST_TIMEOUT");
statusCodes.put(409, "CONFLICT");
statusCodes.put(410, "GONE");
statusCodes.put(411, "LENGTH_REQUIRED");
statusCodes.put(412, "PRECONDITION_FAILED");
statusCodes.put(413, "REQUEST_ENTITY_TOO_LARGE");
statusCodes.put(414, "REQUEST_URI_TOO_LONG");
statusCodes.put(415, "UNSUPPORTED_MEDIA_TYPE");
statusCodes.put(416, "REQUESTED_RANGE_NOT_SATISFIABLE");
statusCodes.put(417, "EXPECTATION_FAILED");
statusCodes.put(418, "I_AM_A_TEAPOT");
statusCodes.put(419, "INSUFFICIENT_SPACE_ON_RESOURCE");
statusCodes.put(420, "METHOD_FAILURE");
statusCodes.put(421, "DESTINATION_LOCKED");
statusCodes.put(422, "UNPROCESSABLE_ENTITY");
statusCodes.put(423, "LOCKED");
statusCodes.put(424, "FAILED_DEPENDENCY");
statusCodes.put(426, "UPGRADE_REQUIRED");
statusCodes.put(428, "PRECONDITION_REQUIRED");
statusCodes.put(429, "TOO_MANY_REQUESTS");
statusCodes.put(431, "REQUEST_HEADER_FIELDS_TOO_LARGE");
statusCodes.put(500, "INTERNAL_SERVER_ERROR");
statusCodes.put(501, "NOT_IMPLEMENTED");
statusCodes.put(502, "BAD_GATEWAY");
statusCodes.put(503, "SERVICE_UNAVAILABLE");
statusCodes.put(504, "GATEWAY_TIMEOUT");
statusCodes.put(505, "HTTP_VERSION_NOT_SUPPORTED");
statusCodes.put(506, "VARIANT_ALSO_NEGOTIATES");
statusCodes.put(507, "INSUFFICIENT_STORAGE");
statusCodes.put(508, "LOOP_DETECTED");
statusCodes.put(509, "BANDWIDTH_LIMIT_EXCEEDED");
statusCodes.put(510, "NOT_EXTENDED");
statusCodes.put(511, "NETWORK_AUTHENTICATION_REQUIRED");
}
@Test
public void fromMapToEnum() {
for (Map.Entry<Integer, String> entry : statusCodes.entrySet()) {
int value = entry.getKey();
HttpStatus status = HttpStatus.valueOf(value);
assertEquals("Invalid value", value, status.value());
assertEquals("Invalid name for [" + value + "]", entry.getValue(), status.name());
}
}
@Test
public void fromEnumToMap() {
for (HttpStatus status : HttpStatus.values()) {
int value = status.value();
if (value == 302) {
continue;
}
assertTrue("Map has no value for [" + value + "]", statusCodes.containsKey(value));
assertEquals("Invalid name for [" + value + "]", statusCodes.get(value), status.name());
}
}
}

View File

@@ -173,9 +173,12 @@ public class MediaTypeTests {
MediaType.parseMediaType("text/html; charset=foo-bar");
}
// SPR-8917
@Test
public void parseMediaTypeQuotedParameterValue() {
MediaType.parseMediaType("audio/*;attr=\"v>alue\"");
MediaType mediaType = MediaType.parseMediaType("audio/*;attr=\"v>alue\"");
assertEquals("\"v>alue\"", mediaType.getParameter("attr"));
}
@Test(expected = IllegalArgumentException.class)

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.
@@ -291,6 +291,10 @@ public class InterceptingClientHttpRequestFactoryTests {
return statusCode;
}
public int getRawStatusCode() throws IOException {
return statusCode.value();
}
public String getStatusText() throws IOException {
return statusText;
}
@@ -300,7 +304,7 @@ public class InterceptingClientHttpRequestFactoryTests {
}
public InputStream getBody() throws IOException {
return null; //To change body of implemented methods use File | Settings | File Templates.
return null;
}
public void close() {

View File

@@ -128,6 +128,9 @@ public class UriUtilsTests {
assertEquals("Invalid encoded URI", "http://example.com/query=foo@bar",
UriUtils.encodeUri("http://example.com/query=foo@bar", ENC));
// SPR-8974
assertEquals("http://example.org?format=json&url=http://another.com?foo=bar",
UriUtils.encodeUri("http://example.org?format=json&url=http://another.com?foo=bar", ENC));
}
@Test