Polishing (backported from 4.1.x)

This commit is contained in:
Juergen Hoeller
2015-12-09 17:10:34 +01:00
parent c0e5d00e56
commit 12eb893e5f
13 changed files with 188 additions and 179 deletions

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2014 the original author or authors. * Copyright 2002-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -234,7 +234,7 @@ public class JibxMarshaller extends AbstractMarshaller implements InitializingBe
public boolean supports(Class<?> clazz) { public boolean supports(Class<?> clazz) {
Assert.notNull(clazz, "'clazz' must not be null"); Assert.notNull(clazz, "Class must not be null");
if (this.targetClass != null) { if (this.targetClass != null) {
return this.targetClass.equals(clazz); return this.targetClass.equals(clazz);
} }

View File

@@ -1,11 +1,11 @@
/* /*
* Copyright 2002-2014 the original author or authors. * Copyright 2002-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
@@ -43,7 +43,8 @@ import org.springframework.util.StringUtils;
/** /**
* Represents HTTP request and response headers, mapping string header names to list of string values. * Represents HTTP request and response headers, mapping string header names to list of string values.
* *
* <p>In addition to the normal methods defined by {@link Map}, this class offers the following convenience methods: * <p>In addition to the normal methods defined by {@link Map}, this class offers the following
* convenience methods:
* <ul> * <ul>
* <li>{@link #getFirst(String)} returns the first value associated with a given header name</li> * <li>{@link #getFirst(String)} returns the first value associated with a given header name</li>
* <li>{@link #add(String, String)} adds a header value to the list of values for a header name</li> * <li>{@link #add(String, String)} adds a header value to the list of values for a header name</li>
@@ -134,18 +135,19 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
return new HttpHeaders(headers, true); return new HttpHeaders(headers, true);
} }
/** /**
* Set the list of acceptable {@linkplain MediaType media types}, as specified by the {@code Accept} header. * Set the list of acceptable {@linkplain MediaType media types},
* @param acceptableMediaTypes the acceptable media types * as specified by the {@code Accept} header.
*/ */
public void setAccept(List<MediaType> acceptableMediaTypes) { public void setAccept(List<MediaType> acceptableMediaTypes) {
set(ACCEPT, MediaType.toString(acceptableMediaTypes)); set(ACCEPT, MediaType.toString(acceptableMediaTypes));
} }
/** /**
* Return the list of acceptable {@linkplain MediaType media types}, as specified by the {@code Accept} header. * Return the list of acceptable {@linkplain MediaType media types},
* as specified by the {@code Accept} header.
* <p>Returns an empty list when the acceptable media types are unspecified. * <p>Returns an empty list when the acceptable media types are unspecified.
* @return the acceptable media types
*/ */
public List<MediaType> getAccept() { public List<MediaType> getAccept() {
String value = getFirst(ACCEPT); String value = getFirst(ACCEPT);
@@ -164,8 +166,8 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
} }
/** /**
* Set the list of acceptable {@linkplain Charset charsets}, as specified by the {@code Accept-Charset} header. * Set the list of acceptable {@linkplain Charset charsets},
* @param acceptableCharsets the acceptable charsets * as specified by the {@code Accept-Charset} header.
*/ */
public void setAcceptCharset(List<Charset> acceptableCharsets) { public void setAcceptCharset(List<Charset> acceptableCharsets) {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
@@ -180,9 +182,8 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
} }
/** /**
* Return the list of acceptable {@linkplain Charset charsets}, as specified by the {@code Accept-Charset} * Return the list of acceptable {@linkplain Charset charsets},
* header. * as specified by the {@code Accept-Charset} header.
* @return the acceptable charsets
*/ */
public List<Charset> getAcceptCharset() { public List<Charset> getAcceptCharset() {
List<Charset> result = new ArrayList<Charset>(); List<Charset> result = new ArrayList<Charset>();
@@ -207,27 +208,27 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
} }
/** /**
* Set the set of allowed {@link HttpMethod HTTP methods}, as specified by the {@code Allow} header. * Set the set of allowed {@link HttpMethod HTTP methods},
* @param allowedMethods the allowed methods * as specified by the {@code Allow} header.
*/ */
public void setAllow(Set<HttpMethod> allowedMethods) { public void setAllow(Set<HttpMethod> allowedMethods) {
set(ALLOW, StringUtils.collectionToCommaDelimitedString(allowedMethods)); set(ALLOW, StringUtils.collectionToCommaDelimitedString(allowedMethods));
} }
/** /**
* Return the set of allowed {@link HttpMethod HTTP methods}, as specified by the {@code Allow} header. * Return the set of allowed {@link HttpMethod HTTP methods},
* as specified by the {@code Allow} header.
* <p>Returns an empty set when the allowed methods are unspecified. * <p>Returns an empty set when the allowed methods are unspecified.
* @return the allowed methods
*/ */
public Set<HttpMethod> getAllow() { public Set<HttpMethod> getAllow() {
String value = getFirst(ALLOW); String value = getFirst(ALLOW);
if (!StringUtils.isEmpty(value)) { if (!StringUtils.isEmpty(value)) {
List<HttpMethod> allowedMethod = new ArrayList<HttpMethod>(5); List<HttpMethod> result = new LinkedList<HttpMethod>();
String[] tokens = value.split(",\\s*"); String[] tokens = value.split(",\\s*");
for (String token : tokens) { for (String token : tokens) {
allowedMethod.add(HttpMethod.valueOf(token)); result.add(HttpMethod.valueOf(token));
} }
return EnumSet.copyOf(allowedMethod); return EnumSet.copyOf(result);
} }
else { else {
return EnumSet.noneOf(HttpMethod.class); return EnumSet.noneOf(HttpMethod.class);
@@ -235,25 +236,24 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
} }
/** /**
* Sets the (new) value of the {@code Cache-Control} header. * Set the (new) value of the {@code Cache-Control} header.
* @param cacheControl the value of the header
*/ */
public void setCacheControl(String cacheControl) { public void setCacheControl(String cacheControl) {
set(CACHE_CONTROL, cacheControl); set(CACHE_CONTROL, cacheControl);
} }
/** /**
* Returns the value of the {@code Cache-Control} header. * Return the value of the {@code Cache-Control} header.
* @return the value of the header
*/ */
public String getCacheControl() { public String getCacheControl() {
return getFirst(CACHE_CONTROL); return getFirst(CACHE_CONTROL);
} }
/** /**
* Sets the (new) value of the {@code Content-Disposition} header for {@code form-data}. * Set the (new) value of the {@code Content-Disposition} header
* for {@code form-data}.
* @param name the control name * @param name the control name
* @param filename the filename, may be {@code null} * @param filename the filename (may be {@code null})
*/ */
public void setContentDispositionFormData(String name, String filename) { public void setContentDispositionFormData(String name, String filename) {
Assert.notNull(name, "'name' must not be null"); Assert.notNull(name, "'name' must not be null");
@@ -267,17 +267,17 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
} }
/** /**
* Set the length of the body in bytes, as specified by the {@code Content-Length} header. * Set the length of the body in bytes, as specified by the
* @param contentLength the content length * {@code Content-Length} header.
*/ */
public void setContentLength(long contentLength) { public void setContentLength(long contentLength) {
set(CONTENT_LENGTH, Long.toString(contentLength)); set(CONTENT_LENGTH, Long.toString(contentLength));
} }
/** /**
* Return the length of the body in bytes, as specified by the {@code Content-Length} header. * Return the length of the body in bytes, as specified by the
* {@code Content-Length} header.
* <p>Returns -1 when the content-length is unknown. * <p>Returns -1 when the content-length is unknown.
* @return the content length
*/ */
public long getContentLength() { public long getContentLength() {
String value = getFirst(CONTENT_LENGTH); String value = getFirst(CONTENT_LENGTH);
@@ -285,8 +285,8 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
} }
/** /**
* Set the {@linkplain MediaType media type} of the body, as specified by the {@code Content-Type} header. * Set the {@linkplain MediaType media type} of the body,
* @param mediaType the media type * as specified by the {@code Content-Type} header.
*/ */
public void setContentType(MediaType mediaType) { public void setContentType(MediaType mediaType) {
Assert.isTrue(!mediaType.isWildcardType(), "'Content-Type' cannot contain wildcard type '*'"); Assert.isTrue(!mediaType.isWildcardType(), "'Content-Type' cannot contain wildcard type '*'");
@@ -295,9 +295,9 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
} }
/** /**
* Return the {@linkplain MediaType media type} of the body, as specified by the {@code Content-Type} header. * Return the {@linkplain MediaType media type} of the body, as specified
* by the {@code Content-Type} header.
* <p>Returns {@code null} when the content-type is unknown. * <p>Returns {@code null} when the content-type is unknown.
* @return the content type
*/ */
public MediaType getContentType() { public MediaType getContentType() {
String value = getFirst(CONTENT_TYPE); String value = getFirst(CONTENT_TYPE);
@@ -305,18 +305,20 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
} }
/** /**
* Sets the date and time at which the message was created, as specified by the {@code Date} header. * Set the date and time at which the message was created, as specified
* <p>The date should be specified as the number of milliseconds since January 1, 1970 GMT. * by the {@code Date} header.
* @param date the date * <p>The date should be specified as the number of milliseconds since
* January 1, 1970 GMT.
*/ */
public void setDate(long date) { public void setDate(long date) {
setDate(DATE, date); setDate(DATE, date);
} }
/** /**
* Returns the date and time at which the message was created, as specified by the {@code Date} header. * Return the date and time at which the message was created, as specified
* <p>The date is returned as the number of milliseconds since January 1, 1970 GMT. Returns -1 when the date is unknown. * by the {@code Date} header.
* @return the creation date/time * <p>The date is returned as the number of milliseconds since
* January 1, 1970 GMT. Returns -1 when the date is unknown.
* @throws IllegalArgumentException if the value can't be converted to a date * @throws IllegalArgumentException if the value can't be converted to a date
*/ */
public long getDate() { public long getDate() {
@@ -324,41 +326,39 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
} }
/** /**
* Sets the (new) entity tag of the body, as specified by the {@code ETag} header. * Set the (new) entity tag of the body, as specified by the {@code ETag} header.
* @param eTag the new entity tag
*/ */
public void setETag(String eTag) { public void setETag(String eTag) {
if (eTag != null) { if (eTag != null) {
Assert.isTrue(eTag.startsWith("\"") || eTag.startsWith("W/"), "Invalid eTag, does not start with W/ or \""); Assert.isTrue(eTag.startsWith("\"") || eTag.startsWith("W/"),
"Invalid eTag, does not start with W/ or \"");
Assert.isTrue(eTag.endsWith("\""), "Invalid eTag, does not end with \""); Assert.isTrue(eTag.endsWith("\""), "Invalid eTag, does not end with \"");
} }
set(ETAG, eTag); set(ETAG, eTag);
} }
/** /**
* Returns the entity tag of the body, as specified by the {@code ETag} header. * Return the entity tag of the body, as specified by the {@code ETag} header.
* @return the entity tag
*/ */
public String getETag() { public String getETag() {
return getFirst(ETAG); return getFirst(ETAG);
} }
/** /**
* Sets the date and time at which the message is no longer valid, as specified by the {@code Expires} header. * Set the date and time at which the message is no longer valid,
* <p>The date should be specified as the number of milliseconds since January 1, 1970 GMT. * as specified by the {@code Expires} header.
* @param expires the new expires header value * <p>The date should be specified as the number of milliseconds since
* January 1, 1970 GMT.
*/ */
public void setExpires(long expires) { public void setExpires(long expires) {
setDate(EXPIRES, expires); setDate(EXPIRES, expires);
} }
/** /**
* Returns the date and time at which the message is no longer valid, as specified by * Return the date and time at which the message is no longer valid,
* the {@code Expires} header. * as specified by the {@code Expires} header.
* <p>The date is returned as the number of milliseconds since January 1, 1970 GMT. * <p>The date is returned as the number of milliseconds since
* Returns -1 when the date is unknown. * January 1, 1970 GMT. Returns -1 when the date is unknown.
*
* @return the expires value
*/ */
public long getExpires() { public long getExpires() {
try { try {
@@ -370,18 +370,18 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
} }
/** /**
* Sets the (new) value of the {@code If-Modified-Since} header. * Set the (new) value of the {@code If-Modified-Since} header.
* <p>The date should be specified as the number of milliseconds since January 1, 1970 GMT. * <p>The date should be specified as the number of milliseconds since
* @param ifModifiedSince the new value of the header * January 1, 1970 GMT.
*/ */
public void setIfModifiedSince(long ifModifiedSince) { public void setIfModifiedSince(long ifModifiedSince) {
setDate(IF_MODIFIED_SINCE, ifModifiedSince); setDate(IF_MODIFIED_SINCE, ifModifiedSince);
} }
/** /**
* Returns the value of the {@code IfModifiedSince} header. * Return the value of the {@code IfModifiedSince} header.
* <p>The date is returned as the number of milliseconds since January 1, 1970 GMT. Returns -1 when the date is unknown. * <p>The date is returned as the number of milliseconds since
* @return the header value * January 1, 1970 GMT. Returns -1 when the date is unknown.
* @deprecated use {@link #getIfModifiedSince()} * @deprecated use {@link #getIfModifiedSince()}
*/ */
@Deprecated @Deprecated
@@ -390,25 +390,23 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
} }
/** /**
* Returns the value of the {@code If-Modified-Since} header. * Return the value of the {@code If-Modified-Since} header.
* <p>The date is returned as the number of milliseconds since January 1, 1970 GMT. Returns -1 when the date is unknown. * <p>The date is returned as the number of milliseconds since
* @return the header value * January 1, 1970 GMT. Returns -1 when the date is unknown.
*/ */
public long getIfModifiedSince() { public long getIfModifiedSince() {
return getFirstDate(IF_MODIFIED_SINCE); return getFirstDate(IF_MODIFIED_SINCE);
} }
/** /**
* Sets the (new) value of the {@code If-None-Match} header. * Set the (new) value of the {@code If-None-Match} header.
* @param ifNoneMatch the new value of the header
*/ */
public void setIfNoneMatch(String ifNoneMatch) { public void setIfNoneMatch(String ifNoneMatch) {
set(IF_NONE_MATCH, ifNoneMatch); set(IF_NONE_MATCH, ifNoneMatch);
} }
/** /**
* Sets the (new) values of the {@code If-None-Match} header. * Set the (new) values of the {@code If-None-Match} header.
* @param ifNoneMatchList the new value of the header
*/ */
public void setIfNoneMatch(List<String> ifNoneMatchList) { public void setIfNoneMatch(List<String> ifNoneMatchList) {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
@@ -423,8 +421,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
} }
/** /**
* Returns the value of the {@code If-None-Match} header. * Return the value of the {@code If-None-Match} header.
* @return the header value
*/ */
public List<String> getIfNoneMatch() { public List<String> getIfNoneMatch() {
List<String> result = new ArrayList<String>(); List<String> result = new ArrayList<String>();
@@ -439,35 +436,37 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
} }
/** /**
* Sets the time the resource was last changed, as specified by the {@code Last-Modified} header. * Set the time the resource was last changed, as specified by the
* <p>The date should be specified as the number of milliseconds since January 1, 1970 GMT. * {@code Last-Modified} header.
* @param lastModified the last modified date * <p>The date should be specified as the number of milliseconds since
* January 1, 1970 GMT.
*/ */
public void setLastModified(long lastModified) { public void setLastModified(long lastModified) {
setDate(LAST_MODIFIED, lastModified); setDate(LAST_MODIFIED, lastModified);
} }
/** /**
* Returns the time the resource was last changed, as specified by the {@code Last-Modified} header. * Return the time the resource was last changed, as specified by the
* <p>The date is returned as the number of milliseconds since January 1, 1970 GMT. Returns -1 when the date is unknown. * {@code Last-Modified} header.
* @return the last modified date * <p>The date is returned as the number of milliseconds since
* January 1, 1970 GMT. Returns -1 when the date is unknown.
*/ */
public long getLastModified() { public long getLastModified() {
return getFirstDate(LAST_MODIFIED); return getFirstDate(LAST_MODIFIED);
} }
/** /**
* Set the (new) location of a resource, as specified by the {@code Location} header. * Set the (new) location of a resource,
* @param location the location * as specified by the {@code Location} header.
*/ */
public void setLocation(URI location) { public void setLocation(URI location) {
set(LOCATION, location.toASCIIString()); set(LOCATION, location.toASCIIString());
} }
/** /**
* Return the (new) location of a resource, as specified by the {@code Location} header. * Return the (new) location of a resource
* as specified by the {@code Location} header.
* <p>Returns {@code null} when the location is unknown. * <p>Returns {@code null} when the location is unknown.
* @return the location
*/ */
public URI getLocation() { public URI getLocation() {
String value = getFirst(LOCATION); String value = getFirst(LOCATION);
@@ -475,16 +474,14 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
} }
/** /**
* Sets the (new) value of the {@code Pragma} header. * Set the (new) value of the {@code Pragma} header.
* @param pragma the value of the header
*/ */
public void setPragma(String pragma) { public void setPragma(String pragma) {
set(PRAGMA, pragma); set(PRAGMA, pragma);
} }
/** /**
* Returns the value of the {@code Pragma} header. * Return the value of the {@code Pragma} header.
* @return the value of the header
*/ */
public String getPragma() { public String getPragma() {
return getFirst(PRAGMA); return getFirst(PRAGMA);
@@ -493,9 +490,9 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
// Date methods // Date methods
/** /**
* Parse the first header value for the given header name as a date, return -1 if * Parse the first header value for the given header name as a date,
* there is no value, or raise {@link IllegalArgumentException} if the value cannot be * return -1 if there is no value, or raise {@link IllegalArgumentException}
* parsed as a date. * if the value cannot be parsed as a date.
*/ */
public long getFirstDate(String headerName) { public long getFirstDate(String headerName) {
String headerValue = getFirst(headerName); String headerValue = getFirst(headerName);
@@ -508,7 +505,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
try { try {
return simpleDateFormat.parse(headerValue).getTime(); return simpleDateFormat.parse(headerValue).getTime();
} }
catch (ParseException e) { catch (ParseException ex) {
// ignore // ignore
} }
} }
@@ -532,23 +529,23 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
/** /**
* Return the first header value for the given header name, if any. * Return the first header value for the given header name, if any.
* @param headerName the header name * @param headerName the header name
* @return the first header value; or {@code null} * @return the first header value, or {@code null} if none
*/ */
public String getFirst(String headerName) { public String getFirst(String headerName) {
List<String> headerValues = headers.get(headerName); List<String> headerValues = this.headers.get(headerName);
return headerValues != null ? headerValues.get(0) : null; return (headerValues != null ? headerValues.get(0) : null);
} }
/** /**
* Add the given, single header value under the given name. * Add the given, single header value under the given name.
* @param headerName the header name * @param headerName the header name
* @param headerValue the header value * @param headerValue the header value
* @throws UnsupportedOperationException if adding headers is not supported * @throws UnsupportedOperationException if adding headers is not supported
* @see #put(String, List) * @see #put(String, List)
* @see #set(String, String) * @see #set(String, String)
*/ */
public void add(String headerName, String headerValue) { public void add(String headerName, String headerValue) {
List<String> headerValues = headers.get(headerName); List<String> headerValues = this.headers.get(headerName);
if (headerValues == null) { if (headerValues == null) {
headerValues = new LinkedList<String>(); headerValues = new LinkedList<String>();
this.headers.put(headerName, headerValues); this.headers.put(headerName, headerValues);
@@ -558,7 +555,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
/** /**
* Set the given, single header value under the given name. * Set the given, single header value under the given name.
* @param headerName the header name * @param headerName the header name
* @param headerValue the header value * @param headerValue the header value
* @throws UnsupportedOperationException if adding headers is not supported * @throws UnsupportedOperationException if adding headers is not supported
* @see #put(String, List) * @see #put(String, List)
@@ -567,7 +564,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
public void set(String headerName, String headerValue) { public void set(String headerName, String headerValue) {
List<String> headerValues = new LinkedList<String>(); List<String> headerValues = new LinkedList<String>();
headerValues.add(headerValue); headerValues.add(headerValue);
headers.put(headerName, headerValues); this.headers.put(headerName, headerValues);
} }
public void setAll(Map<String, String> values) { public void setAll(Map<String, String> values) {
@@ -578,7 +575,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
public Map<String, String> toSingleValueMap() { public Map<String, String> toSingleValueMap() {
LinkedHashMap<String, String> singleValueMap = new LinkedHashMap<String,String>(this.headers.size()); LinkedHashMap<String, String> singleValueMap = new LinkedHashMap<String,String>(this.headers.size());
for (Entry<String, List<String>> entry : headers.entrySet()) { for (Entry<String, List<String>> entry : this.headers.entrySet()) {
singleValueMap.put(entry.getKey(), entry.getValue().get(0)); singleValueMap.put(entry.getKey(), entry.getValue().get(0));
} }
return singleValueMap; return singleValueMap;
@@ -614,8 +611,8 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
return this.headers.remove(key); return this.headers.remove(key);
} }
public void putAll(Map<? extends String, ? extends List<String>> m) { public void putAll(Map<? extends String, ? extends List<String>> map) {
this.headers.putAll(m); this.headers.putAll(map);
} }
public void clear() { public void clear() {

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2012 the original author or authors. * Copyright 2002-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -26,6 +26,6 @@ package org.springframework.http;
*/ */
public enum HttpMethod { public enum HttpMethod {
GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE;
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2011 the original author or authors. * Copyright 2002-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -23,7 +23,8 @@ import org.springframework.http.HttpMethod;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
* Abstract base class for {@link ClientHttpRequestFactory} implementations that decorate another request factory. * Abstract base class for {@link ClientHttpRequestFactory} implementations
* that decorate another request factory.
* *
* @author Arjen Poutsma * @author Arjen Poutsma
* @since 3.1 * @since 3.1
@@ -34,11 +35,11 @@ public abstract class AbstractClientHttpRequestFactoryWrapper implements ClientH
/** /**
* Creates a {@code AbstractClientHttpRequestFactoryWrapper} wrapping the given request factory. * Create a {@code AbstractClientHttpRequestFactoryWrapper} wrapping the given request factory.
* @param requestFactory the request factory to be wrapped * @param requestFactory the request factory to be wrapped
*/ */
protected AbstractClientHttpRequestFactoryWrapper(ClientHttpRequestFactory requestFactory) { protected AbstractClientHttpRequestFactoryWrapper(ClientHttpRequestFactory requestFactory) {
Assert.notNull(requestFactory, "'requestFactory' must not be null"); Assert.notNull(requestFactory, "ClientHttpRequestFactory must not be null");
this.requestFactory = requestFactory; this.requestFactory = requestFactory;
} }
@@ -49,12 +50,12 @@ public abstract class AbstractClientHttpRequestFactoryWrapper implements ClientH
* {@linkplain #AbstractClientHttpRequestFactoryWrapper(ClientHttpRequestFactory) constructor}. * {@linkplain #AbstractClientHttpRequestFactoryWrapper(ClientHttpRequestFactory) constructor}.
*/ */
public final ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException { public final ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
return createRequest(uri, httpMethod, requestFactory); return createRequest(uri, httpMethod, this.requestFactory);
} }
/** /**
* Create a new {@link ClientHttpRequest} for the specified URI and HTTP method by using the * Create a new {@link ClientHttpRequest} for the specified URI and HTTP method
* passed-on request factory. * by using the passed-on request factory.
* <p>Called from {@link #createRequest(URI, HttpMethod)}. * <p>Called from {@link #createRequest(URI, HttpMethod)}.
* @param uri the URI to create a request for * @param uri the URI to create a request for
* @param httpMethod the HTTP method to execute * @param httpMethod the HTTP method to execute

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2012 the original author or authors. * Copyright 2002-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -43,9 +43,9 @@ import org.springframework.http.HttpMethod;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
* {@link org.springframework.http.client.ClientHttpRequestFactory} implementation that uses * {@link org.springframework.http.client.ClientHttpRequestFactory} implementation that
* <a href="http://hc.apache.org/httpcomponents-client-ga/httpclient/">Apache HttpComponents HttpClient</a> * uses <a href="http://hc.apache.org/httpcomponents-client-ga/">Apache HttpComponents
* to create requests. * HttpClient</a> to create requests.
* *
* <p>Allows to use a pre-configured {@link HttpClient} instance - * <p>Allows to use a pre-configured {@link HttpClient} instance -
* potentially with authentication, HTTP connection pooling, etc. * potentially with authentication, HTTP connection pooling, etc.
@@ -144,20 +144,20 @@ public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequest
switch (httpMethod) { switch (httpMethod) {
case GET: case GET:
return new HttpGet(uri); return new HttpGet(uri);
case DELETE:
return new HttpDelete(uri);
case HEAD: case HEAD:
return new HttpHead(uri); return new HttpHead(uri);
case OPTIONS:
return new HttpOptions(uri);
case POST: case POST:
return new HttpPost(uri); return new HttpPost(uri);
case PUT: case PUT:
return new HttpPut(uri); return new HttpPut(uri);
case TRACE:
return new HttpTrace(uri);
case PATCH: case PATCH:
return new HttpPatch(uri); return new HttpPatch(uri);
case DELETE:
return new HttpDelete(uri);
case OPTIONS:
return new HttpOptions(uri);
case TRACE:
return new HttpTrace(uri);
default: default:
throw new IllegalArgumentException("Invalid HTTP method: " + httpMethod); throw new IllegalArgumentException("Invalid HTTP method: " + httpMethod);
} }
@@ -183,6 +183,7 @@ public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequest
return null; return null;
} }
/** /**
* Shutdown hook that closes the underlying * Shutdown hook that closes the underlying
* {@link org.apache.http.conn.ClientConnectionManager ClientConnectionManager}'s * {@link org.apache.http.conn.ClientConnectionManager ClientConnectionManager}'s

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2013 the original author or authors. * Copyright 2002-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -42,49 +42,48 @@ class InterceptingClientHttpRequest extends AbstractBufferingClientHttpRequest {
private URI uri; private URI uri;
protected InterceptingClientHttpRequest(ClientHttpRequestFactory requestFactory, protected InterceptingClientHttpRequest(ClientHttpRequestFactory requestFactory,
List<ClientHttpRequestInterceptor> interceptors, List<ClientHttpRequestInterceptor> interceptors, URI uri, HttpMethod method) {
URI uri,
HttpMethod method) {
this.requestFactory = requestFactory; this.requestFactory = requestFactory;
this.interceptors = interceptors; this.interceptors = interceptors;
this.method = method; this.method = method;
this.uri = uri; this.uri = uri;
} }
public HttpMethod getMethod() { public HttpMethod getMethod() {
return method; return this.method;
} }
public URI getURI() { public URI getURI() {
return uri; return this.uri;
} }
@Override @Override
protected final ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException { protected final ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException {
RequestExecution requestExecution = new RequestExecution(); InterceptingRequestExecution requestExecution = new InterceptingRequestExecution();
return requestExecution.execute(this, bufferedOutput); return requestExecution.execute(this, bufferedOutput);
} }
private class RequestExecution implements ClientHttpRequestExecution {
private class InterceptingRequestExecution implements ClientHttpRequestExecution {
private final Iterator<ClientHttpRequestInterceptor> iterator; private final Iterator<ClientHttpRequestInterceptor> iterator;
private RequestExecution() { public InterceptingRequestExecution() {
this.iterator = interceptors.iterator(); this.iterator = interceptors.iterator();
} }
public ClientHttpResponse execute(HttpRequest request, byte[] body) throws IOException { public ClientHttpResponse execute(HttpRequest request, byte[] body) throws IOException {
if (iterator.hasNext()) { if (this.iterator.hasNext()) {
ClientHttpRequestInterceptor nextInterceptor = iterator.next(); ClientHttpRequestInterceptor nextInterceptor = this.iterator.next();
return nextInterceptor.intercept(request, body, this); return nextInterceptor.intercept(request, body, this);
} }
else { else {
ClientHttpRequest delegate = requestFactory.createRequest(request.getURI(), request.getMethod()); ClientHttpRequest delegate = requestFactory.createRequest(request.getURI(), request.getMethod());
delegate.getHeaders().putAll(request.getHeaders()); delegate.getHeaders().putAll(request.getHeaders());
if (body.length > 0) { if (body.length > 0) {
StreamUtils.copy(body, delegate.getBody()); StreamUtils.copy(body, delegate.getBody());
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2011 the original author or authors. * Copyright 2002-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -32,20 +32,22 @@ public class InterceptingClientHttpRequestFactory extends AbstractClientHttpRequ
private final List<ClientHttpRequestInterceptor> interceptors; private final List<ClientHttpRequestInterceptor> interceptors;
/** /**
* Creates a new instance of the {@code InterceptingClientHttpRequestFactory} with the given parameters. * Create a new instance of the {@code InterceptingClientHttpRequestFactory} with the given parameters.
*
* @param requestFactory the request factory to wrap * @param requestFactory the request factory to wrap
* @param interceptors the interceptors that are to be applied. Can be {@code null}. * @param interceptors the interceptors that are to be applied (can be {@code null})
*/ */
public InterceptingClientHttpRequestFactory(ClientHttpRequestFactory requestFactory, public InterceptingClientHttpRequestFactory(ClientHttpRequestFactory requestFactory,
List<ClientHttpRequestInterceptor> interceptors) { List<ClientHttpRequestInterceptor> interceptors) {
super(requestFactory); super(requestFactory);
this.interceptors = interceptors != null ? interceptors : Collections.<ClientHttpRequestInterceptor>emptyList(); this.interceptors = (interceptors != null ? interceptors : Collections.<ClientHttpRequestInterceptor>emptyList());
} }
@Override @Override
protected ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod, ClientHttpRequestFactory requestFactory) { protected ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod, ClientHttpRequestFactory requestFactory) {
return new InterceptingClientHttpRequest(requestFactory, interceptors, uri, httpMethod); return new InterceptingClientHttpRequest(requestFactory, this.interceptors, uri, httpMethod);
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2014 the original author or authors. * Copyright 2002-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -160,19 +160,23 @@ public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory
if (this.readTimeout >= 0) { if (this.readTimeout >= 0) {
connection.setReadTimeout(this.readTimeout); connection.setReadTimeout(this.readTimeout);
} }
connection.setDoInput(true); connection.setDoInput(true);
if ("GET".equals(httpMethod)) { if ("GET".equals(httpMethod)) {
connection.setInstanceFollowRedirects(true); connection.setInstanceFollowRedirects(true);
} }
else { else {
connection.setInstanceFollowRedirects(false); connection.setInstanceFollowRedirects(false);
} }
if ("PUT".equals(httpMethod) || "POST".equals(httpMethod) || "PATCH".equals(httpMethod)) {
if ("POST".equals(httpMethod) || "PUT".equals(httpMethod) || "PATCH".equals(httpMethod)) {
connection.setDoOutput(true); connection.setDoOutput(true);
} }
else { else {
connection.setDoOutput(false); connection.setDoOutput(false);
} }
connection.setRequestMethod(httpMethod); connection.setRequestMethod(httpMethod);
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2011 the original author or authors. * Copyright 2002-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -24,8 +24,10 @@ import org.springframework.http.HttpRequest;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
* Provides a convenient implementation of the {@link HttpRequest} interface that can be overridden to adapt the * Provides a convenient implementation of the {@link HttpRequest} interface
* request. Methods default to calling through to the wrapped request object. * that can be overridden to adapt the request.
*
* <p>These methods default to calling through to the wrapped request object.
* *
* @author Arjen Poutsma * @author Arjen Poutsma
* @since 3.1 * @since 3.1
@@ -36,38 +38,38 @@ public class HttpRequestWrapper implements HttpRequest {
/** /**
* Creates a new {@code HttpRequest} wrapping the given request object. * Create a new {@code HttpRequest} wrapping the given request object.
*
* @param request the request object to be wrapped * @param request the request object to be wrapped
*/ */
public HttpRequestWrapper(HttpRequest request) { public HttpRequestWrapper(HttpRequest request) {
Assert.notNull(request, "'request' must not be null"); Assert.notNull(request, "HttpRequest must not be null");
this.request = request; this.request = request;
} }
/** /**
* Returns the wrapped request. * Return the wrapped request.
*/ */
public HttpRequest getRequest() { public HttpRequest getRequest() {
return request; return this.request;
} }
/** /**
* Returns the method of the wrapped request. * Return the method of the wrapped request.
*/ */
public HttpMethod getMethod() { public HttpMethod getMethod() {
return this.request.getMethod(); return this.request.getMethod();
} }
/** /**
* Returns the URI of the wrapped request. * Return the URI of the wrapped request.
*/ */
public URI getURI() { public URI getURI() {
return this.request.getURI(); return this.request.getURI();
} }
/** /**
* Returns the headers of the wrapped request. * Return the headers of the wrapped request.
*/ */
public HttpHeaders getHeaders() { public HttpHeaders getHeaders() {
return this.request.getHeaders(); return this.request.getHeaders();

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2014 the original author or authors. * Copyright 2002-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -142,18 +142,21 @@ public class ServletServerHttpRequest implements ServerHttpRequest {
} }
} }
private boolean isFormPost(HttpServletRequest request) {
return (request.getContentType() != null && request.getContentType().contains(FORM_CONTENT_TYPE) &&
private static boolean isFormPost(HttpServletRequest request) {
String contentType = request.getContentType();
return (contentType != null && contentType.contains(FORM_CONTENT_TYPE) &&
METHOD_POST.equalsIgnoreCase(request.getMethod())); METHOD_POST.equalsIgnoreCase(request.getMethod()));
} }
/** /**
* Use {@link javax.servlet.ServletRequest#getParameterMap()} to reconstruct the * Use {@link javax.servlet.ServletRequest#getParameterMap()} to reconstruct the
* body of a form 'POST' providing a predictable outcome as opposed to reading * body of a form 'POST' providing a predictable outcome as opposed to reading
* from the body, which can fail if any other code has used ServletRequest * from the body, which can fail if any other code has used the ServletRequest
* to access a parameter thus causing the input stream to be "consumed". * to access a parameter, thus causing the input stream to be "consumed".
*/ */
private InputStream getBodyFromServletRequestParameters(HttpServletRequest request) throws IOException { private static InputStream getBodyFromServletRequestParameters(HttpServletRequest request) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream(1024); ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
Writer writer = new OutputStreamWriter(bos, FORM_CHARSET); Writer writer = new OutputStreamWriter(bos, FORM_CHARSET);

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2012 the original author or authors. * Copyright 2002-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -17,16 +17,14 @@
package org.springframework.web.bind.annotation; package org.springframework.web.bind.annotation;
/** /**
* Java 5 enumeration of HTTP request methods. Intended for use * Java 5 enumeration of HTTP request methods. Intended for use with the
* with the {@link RequestMapping#method()} attribute of the * {@link RequestMapping#method()} attribute of the {@link RequestMapping} annotation.
* {@link RequestMapping} annotation.
* *
* <p>Note that, by default, {@link org.springframework.web.servlet.DispatcherServlet} * <p>Note that, by default, {@link org.springframework.web.servlet.DispatcherServlet}
* supports GET, HEAD, POST, PUT, PATCH and DELETE only. DispatcherServlet will * supports GET, HEAD, POST, PUT, PATCH and DELETE only. DispatcherServlet will
* process TRACE and OPTIONS with the default HttpServlet behavior unless * process TRACE and OPTIONS with the default HttpServlet behavior unless explicitly
* explicitly told to dispatch those request types as well: Check out * told to dispatch those request types as well: Check out the "dispatchOptionsRequest"
* the "dispatchOptionsRequest" and "dispatchTraceRequest" properties, * and "dispatchTraceRequest" properties, switching them to "true" if necessary.
* switching them to "true" if necessary.
* *
* @author Juergen Hoeller * @author Juergen Hoeller
* @since 2.5 * @since 2.5

View File

@@ -814,15 +814,13 @@ public abstract class FrameworkServlet extends HttpServletBean {
/** /**
* Override the parent class implementation in order to intercept PATCH * Override the parent class implementation in order to intercept PATCH requests.
* requests.
*/ */
@Override @Override
protected void service(HttpServletRequest request, HttpServletResponse response) protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { throws ServletException, IOException {
String method = request.getMethod(); if (RequestMethod.PATCH.name().equalsIgnoreCase(request.getMethod())) {
if (method.equalsIgnoreCase(RequestMethod.PATCH.name())) {
processRequest(request, response); processRequest(request, response);
} }
else { else {

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2012 the original author or authors. * Copyright 2002-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@ import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.web.HttpMediaTypeException; import org.springframework.web.HttpMediaTypeException;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
@@ -40,34 +41,36 @@ abstract class AbstractMediaTypeExpression implements Comparable<AbstractMediaTy
private final boolean isNegated; private final boolean isNegated;
AbstractMediaTypeExpression(String expression) { AbstractMediaTypeExpression(String expression) {
if (expression.startsWith("!")) { if (expression.startsWith("!")) {
isNegated = true; this.isNegated = true;
expression = expression.substring(1); expression = expression.substring(1);
} }
else { else {
isNegated = false; this.isNegated = false;
} }
this.mediaType = MediaType.parseMediaType(expression); this.mediaType = MediaType.parseMediaType(expression);
} }
AbstractMediaTypeExpression(MediaType mediaType, boolean negated) { AbstractMediaTypeExpression(MediaType mediaType, boolean negated) {
this.mediaType = mediaType; this.mediaType = mediaType;
isNegated = negated; this.isNegated = negated;
} }
public MediaType getMediaType() { public MediaType getMediaType() {
return mediaType; return this.mediaType;
} }
public boolean isNegated() { public boolean isNegated() {
return isNegated; return this.isNegated;
} }
public final boolean match(HttpServletRequest request) { public final boolean match(HttpServletRequest request) {
try { try {
boolean match = matchMediaType(request); boolean match = matchMediaType(request);
return !isNegated ? match : !match; return (!this.isNegated ? match : !match);
} }
catch (HttpMediaTypeException ex) { catch (HttpMediaTypeException ex) {
return false; return false;
@@ -76,6 +79,7 @@ abstract class AbstractMediaTypeExpression implements Comparable<AbstractMediaTy
protected abstract boolean matchMediaType(HttpServletRequest request) throws HttpMediaTypeException; protected abstract boolean matchMediaType(HttpServletRequest request) throws HttpMediaTypeException;
public int compareTo(AbstractMediaTypeExpression other) { public int compareTo(AbstractMediaTypeExpression other) {
return MediaType.SPECIFICITY_COMPARATOR.compare(this.getMediaType(), other.getMediaType()); return MediaType.SPECIFICITY_COMPARATOR.compare(this.getMediaType(), other.getMediaType());
} }
@@ -87,23 +91,23 @@ abstract class AbstractMediaTypeExpression implements Comparable<AbstractMediaTy
} }
if (obj != null && getClass().equals(obj.getClass())) { if (obj != null && getClass().equals(obj.getClass())) {
AbstractMediaTypeExpression other = (AbstractMediaTypeExpression) obj; AbstractMediaTypeExpression other = (AbstractMediaTypeExpression) obj;
return (this.mediaType.equals(other.mediaType)) && (this.isNegated == other.isNegated); return (this.mediaType.equals(other.mediaType) && this.isNegated == other.isNegated);
} }
return false; return false;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return mediaType.hashCode(); return this.mediaType.hashCode();
} }
@Override @Override
public String toString() { public String toString() {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
if (isNegated) { if (this.isNegated) {
builder.append('!'); builder.append('!');
} }
builder.append(mediaType.toString()); builder.append(this.mediaType.toString());
return builder.toString(); return builder.toString();
} }