Consistent use of @Nullable across the codebase (even for internals)
Beyond just formally declaring the current behavior, this revision actually enforces non-null behavior in selected signatures now, not tolerating null values anymore when not explicitly documented. It also changes some utility methods with historic null-in/null-out tolerance towards enforced non-null return values, making them a proper citizen in non-null assignments. Some issues are left as to-do: in particular a thorough revision of spring-test, and a few tests with unclear failures (ignored as "TODO: NULLABLE") to be sorted out in a follow-up commit. Issue: SPR-15540
This commit is contained in:
@@ -22,14 +22,16 @@ import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.*;
|
||||
|
||||
/**
|
||||
* Represent the content disposition type and parameters as defined in RFC 2183.
|
||||
* Represent the Content-Disposition type and parameters as defined in RFC 2183.
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @author Juergen Hoeller
|
||||
* @since 5.0
|
||||
* @see <a href="https://tools.ietf.org/html/rfc2183">RFC 2183</a>
|
||||
*/
|
||||
@@ -49,7 +51,9 @@ public class ContentDisposition {
|
||||
/**
|
||||
* Private constructor. See static factory methods in this class.
|
||||
*/
|
||||
private ContentDisposition(@Nullable String type, @Nullable String name, @Nullable String filename, @Nullable Charset charset, @Nullable Long size) {
|
||||
private ContentDisposition(@Nullable String type, @Nullable String name, @Nullable String filename,
|
||||
@Nullable Charset charset, @Nullable Long size) {
|
||||
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
this.filename = filename;
|
||||
@@ -115,7 +119,7 @@ public class ContentDisposition {
|
||||
* Return an empty content disposition.
|
||||
*/
|
||||
public static ContentDisposition empty() {
|
||||
return new ContentDisposition(null, null, null, null, null);
|
||||
return new ContentDisposition("", null, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,36 +213,28 @@ public class ContentDisposition {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
if (!(other instanceof ContentDisposition)) {
|
||||
return false;
|
||||
}
|
||||
ContentDisposition that = (ContentDisposition) o;
|
||||
if (type != null ? !type.equals(that.type) : that.type != null) {
|
||||
return false;
|
||||
}
|
||||
if (name != null ? !name.equals(that.name) : that.name != null) {
|
||||
return false;
|
||||
}
|
||||
if (filename != null ? !filename.equals(that.filename) : that.filename != null) {
|
||||
return false;
|
||||
}
|
||||
if (charset != null ? !charset.equals(that.charset) : that.charset != null) {
|
||||
return false;
|
||||
}
|
||||
return size != null ? size.equals(that.size) : that.size == null;
|
||||
ContentDisposition otherCd = (ContentDisposition) other;
|
||||
return (ObjectUtils.nullSafeEquals(this.type, otherCd.type) &&
|
||||
ObjectUtils.nullSafeEquals(this.name, otherCd.name) &&
|
||||
ObjectUtils.nullSafeEquals(this.filename, otherCd.filename) &&
|
||||
ObjectUtils.nullSafeEquals(this.charset, otherCd.charset) &&
|
||||
ObjectUtils.nullSafeEquals(this.size, otherCd.size));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = type != null ? type.hashCode() : 0;
|
||||
result = 31 * result + (name != null ? name.hashCode() : 0);
|
||||
result = 31 * result + (filename != null ? filename.hashCode() : 0);
|
||||
result = 31 * result + (charset != null ? charset.hashCode() : 0);
|
||||
result = 31 * result + (size != null ? size.hashCode() : 0);
|
||||
int result = ObjectUtils.nullSafeHashCode(this.type);
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(this.name);
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(this.filename);
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(this.charset);
|
||||
result = 31 * result + ObjectUtils.nullSafeHashCode(this.size);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -248,26 +244,29 @@ public class ContentDisposition {
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder(this.type);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (this.type != null) {
|
||||
sb.append(this.type);
|
||||
}
|
||||
if (this.name != null) {
|
||||
builder.append("; name=\"");
|
||||
builder.append(this.name).append('\"');
|
||||
sb.append("; name=\"");
|
||||
sb.append(this.name).append('\"');
|
||||
}
|
||||
if (this.filename != null) {
|
||||
if(this.charset == null || StandardCharsets.US_ASCII.equals(this.charset)) {
|
||||
builder.append("; filename=\"");
|
||||
builder.append(this.filename).append('\"');
|
||||
sb.append("; filename=\"");
|
||||
sb.append(this.filename).append('\"');
|
||||
}
|
||||
else {
|
||||
builder.append("; filename*=");
|
||||
builder.append(encodeHeaderFieldParam(this.filename, this.charset));
|
||||
sb.append("; filename*=");
|
||||
sb.append(encodeHeaderFieldParam(this.filename, this.charset));
|
||||
}
|
||||
}
|
||||
if (this.size != null) {
|
||||
builder.append("; size=");
|
||||
builder.append(this.size);
|
||||
sb.append("; size=");
|
||||
sb.append(this.size);
|
||||
}
|
||||
return builder.toString();
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -13,8 +13,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.http;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -33,7 +35,7 @@ public class HttpCookie {
|
||||
private final String value;
|
||||
|
||||
|
||||
public HttpCookie(String name, String value) {
|
||||
public HttpCookie(String name, @Nullable String value) {
|
||||
Assert.hasLength(name, "'name' is required and must not be empty.");
|
||||
this.name = name;
|
||||
this.value = (value != null ? value : "");
|
||||
@@ -47,7 +49,7 @@ public class HttpCookie {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cookie value or an empty string, never {@code null}.
|
||||
* Return the cookie value or an empty string (never {@code null}).
|
||||
*/
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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,6 +16,7 @@
|
||||
|
||||
package org.springframework.http;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
@@ -94,7 +95,7 @@ public class HttpEntity<T> {
|
||||
* @param body the entity body
|
||||
* @param headers the entity headers
|
||||
*/
|
||||
public HttpEntity(T body, MultiValueMap<String, String> headers) {
|
||||
public HttpEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers) {
|
||||
this.body = body;
|
||||
HttpHeaders tempHeaders = new HttpHeaders();
|
||||
if (headers != null) {
|
||||
@@ -114,6 +115,7 @@ public class HttpEntity<T> {
|
||||
/**
|
||||
* Returns the body of this entity.
|
||||
*/
|
||||
@Nullable
|
||||
public T getBody() {
|
||||
return this.body;
|
||||
}
|
||||
@@ -127,7 +129,7 @@ public class HttpEntity<T> {
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
public boolean equals(@Nullable Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -467,7 +467,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
*/
|
||||
public List<Locale.LanguageRange> getAcceptLanguage() {
|
||||
String value = getFirst(ACCEPT_LANGUAGE);
|
||||
return StringUtils.hasText(value) ? Locale.LanguageRange.parse(value) : Collections.emptyList();
|
||||
return (StringUtils.hasText(value) ? Locale.LanguageRange.parse(value) : Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -560,6 +560,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
/**
|
||||
* Return the value of the {@code Access-Control-Allow-Origin} response header.
|
||||
*/
|
||||
@Nullable
|
||||
public String getAccessControlAllowOrigin() {
|
||||
return getFieldValues(ACCESS_CONTROL_ALLOW_ORIGIN);
|
||||
}
|
||||
@@ -618,6 +619,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
/**
|
||||
* Return the value of the {@code Access-Control-Request-Method} request header.
|
||||
*/
|
||||
@Nullable
|
||||
public HttpMethod getAccessControlRequestMethod() {
|
||||
return HttpMethod.resolve(getFirst(ACCESS_CONTROL_REQUEST_METHOD));
|
||||
}
|
||||
@@ -708,6 +710,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
/**
|
||||
* Return the value of the {@code Cache-Control} header.
|
||||
*/
|
||||
@Nullable
|
||||
public String getCacheControl() {
|
||||
return getFieldValues(CACHE_CONTROL);
|
||||
}
|
||||
@@ -759,9 +762,16 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
*/
|
||||
public void setContentDispositionFormData(String name, @Nullable String filename, @Nullable Charset charset) {
|
||||
Assert.notNull(name, "'name' must not be null");
|
||||
ContentDisposition disposition = ContentDisposition.builder("form-data")
|
||||
.name(name).filename(filename, charset).build();
|
||||
setContentDisposition(disposition);
|
||||
ContentDisposition.Builder disposition = ContentDisposition.builder("form-data").name(name);
|
||||
if (filename != null) {
|
||||
if (charset != null) {
|
||||
disposition.filename(filename, charset);
|
||||
}
|
||||
else {
|
||||
disposition.filename(filename);
|
||||
}
|
||||
}
|
||||
setContentDisposition(disposition.build());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -884,18 +894,17 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
/**
|
||||
* Set the (new) entity tag of the body, as specified by the {@code ETag} header.
|
||||
*/
|
||||
public void setETag(String eTag) {
|
||||
if (eTag != null) {
|
||||
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 \"");
|
||||
}
|
||||
set(ETAG, eTag);
|
||||
public void setETag(String etag) {
|
||||
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 \"");
|
||||
set(ETAG, etag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the entity tag of the body, as specified by the {@code ETag} header.
|
||||
*/
|
||||
@Nullable
|
||||
public String getETag() {
|
||||
return getFirst(ETAG);
|
||||
}
|
||||
@@ -1096,6 +1105,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
/**
|
||||
* Return the value of the {@code Origin} header.
|
||||
*/
|
||||
@Nullable
|
||||
public String getOrigin() {
|
||||
return getFirst(ORIGIN);
|
||||
}
|
||||
@@ -1110,6 +1120,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
/**
|
||||
* Return the value of the {@code Pragma} header.
|
||||
*/
|
||||
@Nullable
|
||||
public String getPragma() {
|
||||
return getFirst(PRAGMA);
|
||||
}
|
||||
@@ -1141,6 +1152,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
/**
|
||||
* Return the value of the {@code Upgrade} header.
|
||||
*/
|
||||
@Nullable
|
||||
public String getUpgrade() {
|
||||
return getFirst(UPGRADE);
|
||||
}
|
||||
@@ -1288,6 +1300,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
* @return the combined result
|
||||
* @since 4.3
|
||||
*/
|
||||
@Nullable
|
||||
protected String getFieldValues(String headerName) {
|
||||
List<String> headerValues = get(headerName);
|
||||
return (headerValues != null ? toCommaDelimitedString(headerValues) : null);
|
||||
@@ -1399,6 +1412,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public List<String> get(Object key) {
|
||||
return this.headers.get(key);
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ public enum HttpMethod {
|
||||
* @since 4.2.4
|
||||
*/
|
||||
@Nullable
|
||||
public static HttpMethod resolve(String method) {
|
||||
public static HttpMethod resolve(@Nullable String method) {
|
||||
return (method != null ? mappings.get(method) : null);
|
||||
}
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ public abstract class HttpRange {
|
||||
* @return the list of ranges
|
||||
* @throws IllegalArgumentException if the string cannot be parsed
|
||||
*/
|
||||
public static List<HttpRange> parseRanges(String ranges) {
|
||||
public static List<HttpRange> parseRanges(@Nullable String ranges) {
|
||||
if (!StringUtils.hasLength(ranges)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
@@ -220,7 +220,7 @@ public abstract class HttpRange {
|
||||
this.lastPos = lastPos;
|
||||
}
|
||||
|
||||
private void assertPositions(long firstBytePos, Long lastBytePos) {
|
||||
private void assertPositions(long firstBytePos, @Nullable Long lastBytePos) {
|
||||
if (firstBytePos < 0) {
|
||||
throw new IllegalArgumentException("Invalid first byte position: " + firstBytePos);
|
||||
}
|
||||
|
||||
@@ -425,7 +425,7 @@ public class MediaType extends MimeType implements Serializable {
|
||||
* @param other the reference media type with which to compare
|
||||
* @return {@code true} if this media type includes the given media type; {@code false} otherwise
|
||||
*/
|
||||
public boolean includes(MediaType other) {
|
||||
public boolean includes(@Nullable MediaType other) {
|
||||
return super.includes(other);
|
||||
}
|
||||
|
||||
@@ -436,7 +436,7 @@ public class MediaType extends MimeType implements Serializable {
|
||||
* @param other the reference media type with which to compare
|
||||
* @return {@code true} if this media type is compatible with the given media type; {@code false} otherwise
|
||||
*/
|
||||
public boolean isCompatibleWith(MediaType other) {
|
||||
public boolean isCompatibleWith(@Nullable MediaType other) {
|
||||
return super.isCompatibleWith(other);
|
||||
}
|
||||
|
||||
@@ -529,7 +529,7 @@ public class MediaType extends MimeType implements Serializable {
|
||||
* @throws InvalidMediaTypeException if the media type value cannot be parsed
|
||||
* @since 4.3.2
|
||||
*/
|
||||
public static List<MediaType> parseMediaTypes(List<String> mediaTypes) {
|
||||
public static List<MediaType> parseMediaTypes(@Nullable List<String> mediaTypes) {
|
||||
if (CollectionUtils.isEmpty(mediaTypes)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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,8 +27,7 @@ import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Extension of {@link HttpEntity} that adds a {@linkplain HttpMethod method} and
|
||||
* {@linkplain URI uri}.
|
||||
* Used in {@code RestTemplate} and {@code @Controller} methods.
|
||||
* {@linkplain URI uri}. Used in {@code RestTemplate} and {@code @Controller} methods.
|
||||
*
|
||||
* <p>In {@code RestTemplate}, this class is used as parameter in
|
||||
* {@link org.springframework.web.client.RestTemplate#exchange(RequestEntity, Class) exchange()}:
|
||||
@@ -76,7 +75,7 @@ public class RequestEntity<T> extends HttpEntity<T> {
|
||||
* @param url the URL
|
||||
*/
|
||||
public RequestEntity(HttpMethod method, URI url) {
|
||||
this(null, null, method, url);
|
||||
this(null, null, method, url, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,7 +84,7 @@ public class RequestEntity<T> extends HttpEntity<T> {
|
||||
* @param method the method
|
||||
* @param url the URL
|
||||
*/
|
||||
public RequestEntity(T body, HttpMethod method, URI url) {
|
||||
public RequestEntity(@Nullable T body, HttpMethod method, URI url) {
|
||||
this(body, null, method, url, null);
|
||||
}
|
||||
|
||||
@@ -97,7 +96,7 @@ public class RequestEntity<T> extends HttpEntity<T> {
|
||||
* @param type the type used for generic type resolution
|
||||
* @since 4.3
|
||||
*/
|
||||
public RequestEntity(T body, HttpMethod method, URI url, Type type) {
|
||||
public RequestEntity(@Nullable T body, HttpMethod method, URI url, Type type) {
|
||||
this(body, null, method, url, type);
|
||||
}
|
||||
|
||||
@@ -118,7 +117,9 @@ public class RequestEntity<T> extends HttpEntity<T> {
|
||||
* @param method the method
|
||||
* @param url the URL
|
||||
*/
|
||||
public RequestEntity(T body, MultiValueMap<String, String> headers, HttpMethod method, URI url) {
|
||||
public RequestEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers,
|
||||
@Nullable HttpMethod method, URI url) {
|
||||
|
||||
this(body, headers, method, url, null);
|
||||
}
|
||||
|
||||
@@ -131,7 +132,9 @@ public class RequestEntity<T> extends HttpEntity<T> {
|
||||
* @param type the type used for generic type resolution
|
||||
* @since 4.3
|
||||
*/
|
||||
public RequestEntity(T body, MultiValueMap<String, String> headers, HttpMethod method, URI url, Type type) {
|
||||
public RequestEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers,
|
||||
@Nullable HttpMethod method, URI url, @Nullable Type type) {
|
||||
|
||||
super(body, headers);
|
||||
this.method = method;
|
||||
this.url = url;
|
||||
@@ -143,6 +146,7 @@ public class RequestEntity<T> extends HttpEntity<T> {
|
||||
* Return the HTTP method of the request.
|
||||
* @return the HTTP method as an {@code HttpMethod} enum value
|
||||
*/
|
||||
@Nullable
|
||||
public HttpMethod getMethod() {
|
||||
return this.method;
|
||||
}
|
||||
@@ -173,7 +177,7 @@ public class RequestEntity<T> extends HttpEntity<T> {
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
public boolean equals(@Nullable Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
@@ -204,13 +208,9 @@ public class RequestEntity<T> extends HttpEntity<T> {
|
||||
HttpHeaders headers = getHeaders();
|
||||
if (body != null) {
|
||||
builder.append(body);
|
||||
if (headers != null) {
|
||||
builder.append(',');
|
||||
}
|
||||
}
|
||||
if (headers != null) {
|
||||
builder.append(headers);
|
||||
builder.append(',');
|
||||
}
|
||||
builder.append(headers);
|
||||
builder.append('>');
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.util.Arrays;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
@@ -66,7 +67,7 @@ import org.springframework.util.ObjectUtils;
|
||||
*/
|
||||
public class ResponseEntity<T> extends HttpEntity<T> {
|
||||
|
||||
private final Object statusCode;
|
||||
private final Object status;
|
||||
|
||||
|
||||
/**
|
||||
@@ -82,7 +83,7 @@ public class ResponseEntity<T> extends HttpEntity<T> {
|
||||
* @param body the entity body
|
||||
* @param status the status code
|
||||
*/
|
||||
public ResponseEntity(T body, HttpStatus status) {
|
||||
public ResponseEntity(@Nullable T body, HttpStatus status) {
|
||||
this(body, null, status);
|
||||
}
|
||||
|
||||
@@ -101,10 +102,10 @@ public class ResponseEntity<T> extends HttpEntity<T> {
|
||||
* @param headers the entity headers
|
||||
* @param status the status code
|
||||
*/
|
||||
public ResponseEntity(T body, MultiValueMap<String, String> headers, HttpStatus status) {
|
||||
public ResponseEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers, HttpStatus status) {
|
||||
super(body, headers);
|
||||
Assert.notNull(status, "HttpStatus must not be null");
|
||||
this.statusCode = status;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,11 +113,12 @@ public class ResponseEntity<T> extends HttpEntity<T> {
|
||||
* Just used behind the nested builder API.
|
||||
* @param body the entity body
|
||||
* @param headers the entity headers
|
||||
* @param statusCode the status code (as {@code HttpStatus} or as {@code Integer} value)
|
||||
* @param status the status code (as {@code HttpStatus} or as {@code Integer} value)
|
||||
*/
|
||||
private ResponseEntity(T body, MultiValueMap<String, String> headers, Object statusCode) {
|
||||
private ResponseEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers, Object status) {
|
||||
super(body, headers);
|
||||
this.statusCode = statusCode;
|
||||
Assert.notNull(status, "HttpStatus must not be null");
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
|
||||
@@ -125,11 +127,11 @@ public class ResponseEntity<T> extends HttpEntity<T> {
|
||||
* @return the HTTP status as an HttpStatus enum entry
|
||||
*/
|
||||
public HttpStatus getStatusCode() {
|
||||
if (this.statusCode instanceof HttpStatus) {
|
||||
return (HttpStatus) this.statusCode;
|
||||
if (this.status instanceof HttpStatus) {
|
||||
return (HttpStatus) this.status;
|
||||
}
|
||||
else {
|
||||
return HttpStatus.valueOf((Integer) this.statusCode);
|
||||
return HttpStatus.valueOf((Integer) this.status);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,17 +141,17 @@ public class ResponseEntity<T> extends HttpEntity<T> {
|
||||
* @since 4.3
|
||||
*/
|
||||
public int getStatusCodeValue() {
|
||||
if (this.statusCode instanceof HttpStatus) {
|
||||
return ((HttpStatus) this.statusCode).value();
|
||||
if (this.status instanceof HttpStatus) {
|
||||
return ((HttpStatus) this.status).value();
|
||||
}
|
||||
else {
|
||||
return (Integer) this.statusCode;
|
||||
return (Integer) this.status;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
public boolean equals(@Nullable Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
@@ -157,34 +159,30 @@ public class ResponseEntity<T> extends HttpEntity<T> {
|
||||
return false;
|
||||
}
|
||||
ResponseEntity<?> otherEntity = (ResponseEntity<?>) other;
|
||||
return ObjectUtils.nullSafeEquals(this.statusCode, otherEntity.statusCode);
|
||||
return ObjectUtils.nullSafeEquals(this.status, otherEntity.status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (super.hashCode() * 29 + ObjectUtils.nullSafeHashCode(this.statusCode));
|
||||
return (super.hashCode() * 29 + ObjectUtils.nullSafeHashCode(this.status));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder("<");
|
||||
builder.append(this.statusCode.toString());
|
||||
if (this.statusCode instanceof HttpStatus) {
|
||||
builder.append(this.status.toString());
|
||||
if (this.status instanceof HttpStatus) {
|
||||
builder.append(' ');
|
||||
builder.append(((HttpStatus) this.statusCode).getReasonPhrase());
|
||||
builder.append(((HttpStatus) this.status).getReasonPhrase());
|
||||
}
|
||||
builder.append(',');
|
||||
T body = getBody();
|
||||
HttpHeaders headers = getHeaders();
|
||||
if (body != null) {
|
||||
builder.append(body);
|
||||
if (headers != null) {
|
||||
builder.append(',');
|
||||
}
|
||||
}
|
||||
if (headers != null) {
|
||||
builder.append(headers);
|
||||
builder.append(',');
|
||||
}
|
||||
builder.append(headers);
|
||||
builder.append('>');
|
||||
return builder.toString();
|
||||
}
|
||||
@@ -315,7 +313,7 @@ public class ResponseEntity<T> extends HttpEntity<T> {
|
||||
* @since 4.1.2
|
||||
* @see HttpHeaders#add(String, String)
|
||||
*/
|
||||
B headers(HttpHeaders headers);
|
||||
B headers(@Nullable HttpHeaders headers);
|
||||
|
||||
/**
|
||||
* Set the set of allowed {@link HttpMethod HTTP methods}, as specified
|
||||
@@ -328,11 +326,11 @@ public class ResponseEntity<T> extends HttpEntity<T> {
|
||||
|
||||
/**
|
||||
* Set the entity tag of the body, as specified by the {@code ETag} header.
|
||||
* @param eTag the new entity tag
|
||||
* @param etag the new entity tag
|
||||
* @return this builder
|
||||
* @see HttpHeaders#setETag(String)
|
||||
*/
|
||||
B eTag(String eTag);
|
||||
B eTag(String etag);
|
||||
|
||||
/**
|
||||
* Set the time the resource was last changed, as specified by the
|
||||
@@ -415,7 +413,7 @@ public class ResponseEntity<T> extends HttpEntity<T> {
|
||||
* @param body the body of the response entity
|
||||
* @return the built response entity
|
||||
*/
|
||||
<T> ResponseEntity<T> body(T body);
|
||||
<T> ResponseEntity<T> body(@Nullable T body);
|
||||
}
|
||||
|
||||
|
||||
@@ -438,7 +436,7 @@ public class ResponseEntity<T> extends HttpEntity<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BodyBuilder headers(HttpHeaders headers) {
|
||||
public BodyBuilder headers(@Nullable HttpHeaders headers) {
|
||||
if (headers != null) {
|
||||
this.headers.putAll(headers);
|
||||
}
|
||||
@@ -464,16 +462,14 @@ public class ResponseEntity<T> extends HttpEntity<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BodyBuilder eTag(String eTag) {
|
||||
if (eTag != null) {
|
||||
if (!eTag.startsWith("\"") && !eTag.startsWith("W/\"")) {
|
||||
eTag = "\"" + eTag;
|
||||
}
|
||||
if (!eTag.endsWith("\"")) {
|
||||
eTag = eTag + "\"";
|
||||
}
|
||||
public BodyBuilder eTag(String etag) {
|
||||
if (!etag.startsWith("\"") && !etag.startsWith("W/\"")) {
|
||||
etag = "\"" + etag;
|
||||
}
|
||||
this.headers.setETag(eTag);
|
||||
if (!etag.endsWith("\"")) {
|
||||
etag = etag + "\"";
|
||||
}
|
||||
this.headers.setETag(etag);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -510,7 +506,7 @@ public class ResponseEntity<T> extends HttpEntity<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ResponseEntity<T> body(T body) {
|
||||
public <T> ResponseEntity<T> body(@Nullable T body) {
|
||||
return new ResponseEntity<>(body, this.headers, this.statusCode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -97,6 +97,7 @@ public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequest
|
||||
* Return the {@code HttpClient} used for
|
||||
* {@linkplain #createRequest(URI, HttpMethod) synchronous execution}.
|
||||
*/
|
||||
@Nullable
|
||||
public HttpClient getHttpClient() {
|
||||
return this.httpClient;
|
||||
}
|
||||
@@ -219,11 +220,9 @@ public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequest
|
||||
* the factory-level {@link RequestConfig}, if necessary.
|
||||
* @param clientConfig the config held by the current
|
||||
* @return the merged request config
|
||||
* (may be {@code null} if the given client config is {@code null})
|
||||
* @since 4.2
|
||||
*/
|
||||
@Nullable
|
||||
protected RequestConfig mergeRequestConfig(@Nullable RequestConfig clientConfig) {
|
||||
protected RequestConfig mergeRequestConfig(RequestConfig clientConfig) {
|
||||
if (this.requestConfig == null) { // nothing to merge
|
||||
return clientConfig;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import org.apache.http.protocol.HttpContext;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.StreamingHttpOutputMessage;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* {@link ClientHttpRequest} implementation based on
|
||||
@@ -126,12 +127,14 @@ final class HttpComponentsStreamingClientHttpRequest extends AbstractClientHttpR
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Header getContentType() {
|
||||
MediaType contentType = this.headers.getContentType();
|
||||
return (contentType != null ? new BasicHeader("Content-Type", contentType.toString()) : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Header getContentEncoding() {
|
||||
String contentEncoding = this.headers.getFirst("Content-Encoding");
|
||||
return (contentEncoding != null ? new BasicHeader("Content-Encoding", contentEncoding) : null);
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.util.List;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StreamUtils;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
@@ -49,12 +50,11 @@ class InterceptingAsyncClientHttpRequest extends AbstractBufferingAsyncClientHtt
|
||||
|
||||
|
||||
/**
|
||||
* Creates new instance of {@link InterceptingAsyncClientHttpRequest}.
|
||||
*
|
||||
* Create new instance of {@link InterceptingAsyncClientHttpRequest}.
|
||||
* @param requestFactory the async request factory
|
||||
* @param interceptors the list of interceptors
|
||||
* @param uri the request URI
|
||||
* @param httpMethod the HTTP method
|
||||
* @param interceptors the list of interceptors
|
||||
* @param uri the request URI
|
||||
* @param httpMethod the HTTP method
|
||||
*/
|
||||
public InterceptingAsyncClientHttpRequest(AsyncClientHttpRequestFactory requestFactory,
|
||||
List<AsyncClientHttpRequestInterceptor> interceptors, URI uri, HttpMethod httpMethod) {
|
||||
@@ -107,11 +107,12 @@ class InterceptingAsyncClientHttpRequest extends AbstractBufferingAsyncClientHtt
|
||||
}
|
||||
else {
|
||||
URI theUri = request.getURI();
|
||||
HttpMethod theMethod = request.getMethod();
|
||||
HttpHeaders theHeaders = request.getHeaders();
|
||||
HttpMethod method = request.getMethod();
|
||||
HttpHeaders headers = request.getHeaders();
|
||||
|
||||
AsyncClientHttpRequest delegate = requestFactory.createAsyncRequest(theUri, theMethod);
|
||||
delegate.getHeaders().putAll(theHeaders);
|
||||
Assert.state(method != null, "No standard HTTP method");
|
||||
AsyncClientHttpRequest delegate = requestFactory.createAsyncRequest(theUri, method);
|
||||
delegate.getHeaders().putAll(headers);
|
||||
if (body.length > 0) {
|
||||
StreamUtils.copy(body, delegate.getBody());
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Wrapper for a {@link AsyncClientHttpRequestFactory} that has support for
|
||||
@@ -46,7 +47,7 @@ public class InterceptingAsyncClientHttpRequestFactory implements AsyncClientHtt
|
||||
* @param interceptors the list of interceptors to use
|
||||
*/
|
||||
public InterceptingAsyncClientHttpRequestFactory(AsyncClientHttpRequestFactory delegate,
|
||||
List<AsyncClientHttpRequestInterceptor> interceptors) {
|
||||
@Nullable List<AsyncClientHttpRequestInterceptor> interceptors) {
|
||||
|
||||
this.delegate = delegate;
|
||||
this.interceptors = (interceptors != null ? interceptors : Collections.emptyList());
|
||||
|
||||
@@ -25,6 +25,7 @@ import java.util.Map;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
/**
|
||||
@@ -91,7 +92,9 @@ class InterceptingClientHttpRequest extends AbstractBufferingClientHttpRequest {
|
||||
return nextInterceptor.intercept(request, body, this);
|
||||
}
|
||||
else {
|
||||
ClientHttpRequest delegate = requestFactory.createRequest(request.getURI(), request.getMethod());
|
||||
HttpMethod method = request.getMethod();
|
||||
Assert.state(method != null, "No standard HTTP method");
|
||||
ClientHttpRequest delegate = requestFactory.createRequest(request.getURI(), method);
|
||||
for (Map.Entry<String, List<String>> entry : request.getHeaders().entrySet()) {
|
||||
delegate.getHeaders().addAll(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -20,9 +20,11 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
/**
|
||||
* {@link ClientHttpResponse} implementation based on OkHttp 3.x.
|
||||
@@ -57,7 +59,8 @@ class OkHttp3ClientHttpResponse extends AbstractClientHttpResponse {
|
||||
|
||||
@Override
|
||||
public InputStream getBody() throws IOException {
|
||||
return this.response.body().byteStream();
|
||||
ResponseBody body = this.response.body();
|
||||
return (body != null ? body.byteStream() : StreamUtils.emptyInput());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -76,7 +79,10 @@ class OkHttp3ClientHttpResponse extends AbstractClientHttpResponse {
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
this.response.body().close();
|
||||
ResponseBody body = this.response.body();
|
||||
if (body != null) {
|
||||
body.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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,6 +23,7 @@ import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.client.ClientHttpRequestExecution;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.Base64Utils;
|
||||
|
||||
@@ -45,7 +46,7 @@ public class BasicAuthorizationInterceptor implements ClientHttpRequestIntercept
|
||||
* @param username the username to use
|
||||
* @param password the password to use
|
||||
*/
|
||||
public BasicAuthorizationInterceptor(String username, String password) {
|
||||
public BasicAuthorizationInterceptor(String username, @Nullable String password) {
|
||||
Assert.hasLength(username, "Username must not be empty");
|
||||
this.username = username;
|
||||
this.password = (password != null ? password : "");
|
||||
|
||||
@@ -128,12 +128,12 @@ public class DecoderHttpMessageReader<T> implements HttpMessageReader<T> {
|
||||
* or annotations from controller method parameters. By default, delegate to
|
||||
* the decoder if it is an instance of {@link HttpMessageDecoder}.
|
||||
*/
|
||||
protected Map<String, Object> getReadHints(ResolvableType streamType,
|
||||
protected Map<String, Object> getReadHints(ResolvableType actualType,
|
||||
ResolvableType elementType, ServerHttpRequest request, ServerHttpResponse response) {
|
||||
|
||||
if (this.decoder instanceof HttpMessageDecoder) {
|
||||
HttpMessageDecoder<?> httpDecoder = (HttpMessageDecoder<?>) this.decoder;
|
||||
return httpDecoder.getDecodeHints(streamType, elementType, request, response);
|
||||
return httpDecoder.getDecodeHints(actualType, elementType, request, response);
|
||||
}
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ class DefaultClientCodecConfigurer extends AbstractCodecConfigurer implements Cl
|
||||
if (this.sseDecoder != null) {
|
||||
return this.sseDecoder;
|
||||
}
|
||||
return jackson2Present ? jackson2Decoder() : null;
|
||||
return (jackson2Present ? jackson2Decoder() : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -103,13 +103,14 @@ public class EncoderHttpMessageWriter<T> implements HttpMessageWriter<T> {
|
||||
message.writeAndFlushWith(body.map(Flux::just)) : message.writeWith(body));
|
||||
}
|
||||
|
||||
private MediaType updateContentType(ReactiveHttpOutputMessage message, MediaType mediaType) {
|
||||
@Nullable
|
||||
private MediaType updateContentType(ReactiveHttpOutputMessage message, @Nullable MediaType mediaType) {
|
||||
MediaType result = message.getHeaders().getContentType();
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
MediaType fallback = this.defaultMediaType;
|
||||
result = useFallback(mediaType, fallback) ? fallback : mediaType;
|
||||
result = (useFallback(mediaType, fallback) ? fallback : mediaType);
|
||||
if (result != null) {
|
||||
result = addDefaultCharset(result, fallback);
|
||||
message.getHeaders().setContentType(result);
|
||||
@@ -117,29 +118,29 @@ public class EncoderHttpMessageWriter<T> implements HttpMessageWriter<T> {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean useFallback(MediaType main, MediaType fallback) {
|
||||
private static boolean useFallback(@Nullable MediaType main, @Nullable MediaType fallback) {
|
||||
return (main == null || !main.isConcrete() ||
|
||||
main.equals(MediaType.APPLICATION_OCTET_STREAM) && fallback != null);
|
||||
}
|
||||
|
||||
private static MediaType addDefaultCharset(MediaType main, MediaType defaultType) {
|
||||
private static MediaType addDefaultCharset(MediaType main, @Nullable MediaType defaultType) {
|
||||
if (main.getCharset() == null && defaultType != null && defaultType.getCharset() != null) {
|
||||
return new MediaType(main, defaultType.getCharset());
|
||||
}
|
||||
return main;
|
||||
}
|
||||
|
||||
private boolean isStreamingMediaType(MediaType contentType) {
|
||||
return this.encoder instanceof HttpMessageEncoder &&
|
||||
private boolean isStreamingMediaType(@Nullable MediaType contentType) {
|
||||
return (contentType != null && this.encoder instanceof HttpMessageEncoder &&
|
||||
((HttpMessageEncoder<?>) this.encoder).getStreamingMediaTypes().stream()
|
||||
.anyMatch(contentType::isCompatibleWith);
|
||||
.anyMatch(contentType::isCompatibleWith));
|
||||
}
|
||||
|
||||
|
||||
// Server side only...
|
||||
|
||||
@Override
|
||||
public Mono<Void> write(Publisher<? extends T> inputStream, @Nullable ResolvableType actualType,
|
||||
public Mono<Void> write(Publisher<? extends T> inputStream, ResolvableType actualType,
|
||||
ResolvableType elementType, @Nullable MediaType mediaType, ServerHttpRequest request,
|
||||
ServerHttpResponse response, Map<String, Object> hints) {
|
||||
|
||||
@@ -156,7 +157,7 @@ public class EncoderHttpMessageWriter<T> implements HttpMessageWriter<T> {
|
||||
* the encoder if it is an instance of {@link HttpMessageEncoder}.
|
||||
*/
|
||||
protected Map<String, Object> getWriteHints(ResolvableType streamType, ResolvableType elementType,
|
||||
MediaType mediaType, ServerHttpRequest request, ServerHttpResponse response) {
|
||||
@Nullable MediaType mediaType, ServerHttpRequest request, ServerHttpResponse response) {
|
||||
|
||||
if (this.encoder instanceof HttpMessageEncoder) {
|
||||
HttpMessageEncoder<?> httpEncoder = (HttpMessageEncoder<?>) this.encoder;
|
||||
|
||||
@@ -105,7 +105,7 @@ public class FormHttpMessageReader implements HttpMessageReader<MultiValueMap<St
|
||||
});
|
||||
}
|
||||
|
||||
private Charset getMediaTypeCharset(MediaType mediaType) {
|
||||
private Charset getMediaTypeCharset(@Nullable MediaType mediaType) {
|
||||
if (mediaType != null && mediaType.getCharset() != null) {
|
||||
return mediaType.getCharset();
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ public class FormHttpMessageWriter implements HttpMessageWriter<MultiValueMap<St
|
||||
|
||||
}
|
||||
|
||||
private Charset getMediaTypeCharset(MediaType mediaType) {
|
||||
private Charset getMediaTypeCharset(@Nullable MediaType mediaType) {
|
||||
if (mediaType != null && mediaType.getCharset() != null) {
|
||||
return mediaType.getCharset();
|
||||
}
|
||||
|
||||
@@ -37,9 +37,9 @@ public interface HttpMessageDecoder<T> extends Decoder<T> {
|
||||
* target controller method parameter.
|
||||
* @param actualType the actual target type to decode to, possibly a reactive
|
||||
* wrapper and sourced from {@link org.springframework.core.MethodParameter},
|
||||
* i.e. providing access to method parameter annotations.
|
||||
* i.e. providing access to method parameter annotations
|
||||
* @param elementType the element type within {@code Flux/Mono} that we're
|
||||
* trying to decode to.
|
||||
* trying to decode to
|
||||
* @param request the current request
|
||||
* @param response the current response
|
||||
* @return a Map with hints, possibly empty
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.springframework.core.codec.Encoder;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Extension of {@code Encoder} exposing extra methods relevant in the context
|
||||
@@ -54,7 +55,7 @@ public interface HttpMessageEncoder<T> extends Encoder<T> {
|
||||
* @return a Map with hints, possibly empty
|
||||
*/
|
||||
default Map<String, Object> getEncodeHints(ResolvableType actualType, ResolvableType elementType,
|
||||
MediaType mediaType, ServerHttpRequest request, ServerHttpResponse response) {
|
||||
@Nullable MediaType mediaType, ServerHttpRequest request, ServerHttpResponse response) {
|
||||
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ public interface HttpMessageReader<T> {
|
||||
/**
|
||||
* Whether the given object type is supported by this reader.
|
||||
* @param elementType the type of object to check
|
||||
* @param mediaType the media type for the read, possibly {@code null}
|
||||
* @param mediaType the media type for the read (possibly {@code null})
|
||||
* @return {@code true} if readable, {@code false} otherwise
|
||||
*/
|
||||
boolean canRead(ResolvableType elementType, @Nullable MediaType mediaType);
|
||||
|
||||
@@ -74,7 +74,6 @@ public interface HttpMessageWriter<T> {
|
||||
* Server-side only alternative to
|
||||
* {@link #write(Publisher, ResolvableType, MediaType, ReactiveHttpOutputMessage, Map)}
|
||||
* with additional context available.
|
||||
*
|
||||
* @param actualType the actual return type of the method that returned the
|
||||
* value; for annotated controllers, the {@link MethodParameter} can be
|
||||
* accessed via {@link ResolvableType#getSource()}.
|
||||
@@ -85,7 +84,7 @@ public interface HttpMessageWriter<T> {
|
||||
* @param response the current response
|
||||
* @return a {@link Mono} that indicates completion of writing or error
|
||||
*/
|
||||
default Mono<Void> write(Publisher<? extends T> inputStream, @Nullable ResolvableType actualType,
|
||||
default Mono<Void> write(Publisher<? extends T> inputStream, ResolvableType actualType,
|
||||
ResolvableType elementType, @Nullable MediaType mediaType, ServerHttpRequest request,
|
||||
ServerHttpResponse response, Map<String, Object> hints) {
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ public class ResourceHttpMessageWriter implements HttpMessageWriter<Resource> {
|
||||
writeResource(resource, elementType, mediaType, message, hints));
|
||||
}
|
||||
|
||||
private Mono<Void> writeResource(Resource resource, ResolvableType type, MediaType mediaType,
|
||||
private Mono<Void> writeResource(Resource resource, ResolvableType type, @Nullable MediaType mediaType,
|
||||
ReactiveHttpOutputMessage message, Map<String, Object> hints) {
|
||||
|
||||
HttpHeaders headers = message.getHeaders();
|
||||
@@ -133,9 +133,9 @@ public class ResourceHttpMessageWriter implements HttpMessageWriter<Resource> {
|
||||
});
|
||||
}
|
||||
|
||||
private static MediaType getResourceMediaType(MediaType type, Resource resource) {
|
||||
if (type != null && type.isConcrete() && !type.equals(MediaType.APPLICATION_OCTET_STREAM)) {
|
||||
return type;
|
||||
private static MediaType getResourceMediaType(@Nullable MediaType mediaType, Resource resource) {
|
||||
if (mediaType != null && mediaType.isConcrete() && !mediaType.equals(MediaType.APPLICATION_OCTET_STREAM)) {
|
||||
return mediaType;
|
||||
}
|
||||
return MediaTypeFactory.getMediaType(resource).orElse(MediaType.APPLICATION_OCTET_STREAM);
|
||||
}
|
||||
@@ -236,7 +236,7 @@ public class ResourceHttpMessageWriter implements HttpMessageWriter<Resource> {
|
||||
}
|
||||
|
||||
private Mono<Void> encodeAndWriteRegions(Publisher<? extends ResourceRegion> publisher,
|
||||
MediaType mediaType, ReactiveHttpOutputMessage message, Map<String, Object> hints) {
|
||||
@Nullable MediaType mediaType, ReactiveHttpOutputMessage message, Map<String, Object> hints) {
|
||||
|
||||
Flux<DataBuffer> body = this.regionEncoder.encode(
|
||||
publisher, message.bufferFactory(), REGION_TYPE, mediaType, hints);
|
||||
|
||||
@@ -40,19 +40,19 @@ public class ServerSentEvent<T> {
|
||||
|
||||
private final String event;
|
||||
|
||||
private final T data;
|
||||
|
||||
private final Duration retry;
|
||||
|
||||
private final String comment;
|
||||
|
||||
private final T data;
|
||||
|
||||
private ServerSentEvent(String id, String event, T data, Duration retry, String comment) {
|
||||
|
||||
private ServerSentEvent(String id, String event, Duration retry, String comment, T data) {
|
||||
this.id = id;
|
||||
this.event = event;
|
||||
this.data = data;
|
||||
this.retry = retry;
|
||||
this.comment = comment;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
|
||||
@@ -72,14 +72,6 @@ public class ServerSentEvent<T> {
|
||||
return this.event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@code data} field of this event, if available.
|
||||
*/
|
||||
@Nullable
|
||||
public T data() {
|
||||
return this.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@code retry} field of this event, if available.
|
||||
*/
|
||||
@@ -96,11 +88,19 @@ public class ServerSentEvent<T> {
|
||||
return this.comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@code data} field of this event, if available.
|
||||
*/
|
||||
@Nullable
|
||||
public T data() {
|
||||
return this.data;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ("ServerSentEvent [id = '" + this.id + '\'' + ", event='" + this.event + '\'' +
|
||||
", data=" + this.data + ", retry=" + this.retry + ", comment='" + this.comment + '\'' + ']');
|
||||
return ("ServerSentEvent [id = '" + this.id + "\', event='" + this.event + "\', retry=" +
|
||||
this.retry + ", comment='" + this.comment + "', data=" + this.data + ']');
|
||||
}
|
||||
|
||||
|
||||
@@ -132,7 +132,6 @@ public class ServerSentEvent<T> {
|
||||
|
||||
/**
|
||||
* Set the value of the {@code id} field.
|
||||
*
|
||||
* @param id the value of the id field
|
||||
* @return {@code this} builder
|
||||
*/
|
||||
@@ -140,26 +139,13 @@ public class ServerSentEvent<T> {
|
||||
|
||||
/**
|
||||
* Set the value of the {@code event} field.
|
||||
*
|
||||
* @param event the value of the event field
|
||||
* @return {@code this} builder
|
||||
*/
|
||||
Builder<T> event(String event);
|
||||
|
||||
/**
|
||||
* Set the value of the {@code data} field. If the {@code data} argument is a multi-line {@code String}, it
|
||||
* will be turned into multiple {@code data} field lines as defined in Server-Sent Events
|
||||
* W3C recommendation. If {@code data} is not a String, it will be
|
||||
* {@linkplain Jackson2JsonEncoder encoded} into JSON.
|
||||
*
|
||||
* @param data the value of the data field
|
||||
* @return {@code this} builder
|
||||
*/
|
||||
Builder<T> data(T data);
|
||||
|
||||
/**
|
||||
* Set the value of the {@code retry} field.
|
||||
*
|
||||
* @param retry the value of the retry field
|
||||
* @return {@code this} builder
|
||||
*/
|
||||
@@ -167,17 +153,24 @@ public class ServerSentEvent<T> {
|
||||
|
||||
/**
|
||||
* Set SSE comment. If a multi-line comment is provided, it will be turned into multiple
|
||||
* SSE comment lines as defined in Server-Sent Events W3C
|
||||
* recommendation.
|
||||
*
|
||||
* SSE comment lines as defined in Server-Sent Events W3C recommendation.
|
||||
* @param comment the comment to set
|
||||
* @return {@code this} builder
|
||||
*/
|
||||
Builder<T> comment(String comment);
|
||||
|
||||
/**
|
||||
* Set the value of the {@code data} field. If the {@code data} argument is a
|
||||
* multi-line {@code String}, it will be turned into multiple {@code data} field lines
|
||||
* as defined in the Server-Sent Events W3C recommendation. If {@code data} is not a
|
||||
* String, it will be {@linkplain Jackson2JsonEncoder encoded} into JSON.
|
||||
* @param data the value of the data field
|
||||
* @return {@code this} builder
|
||||
*/
|
||||
Builder<T> data(T data);
|
||||
|
||||
/**
|
||||
* Builds the event.
|
||||
*
|
||||
* @return the built event
|
||||
*/
|
||||
ServerSentEvent<T> build();
|
||||
@@ -186,8 +179,6 @@ public class ServerSentEvent<T> {
|
||||
|
||||
private static class BuilderImpl<T> implements Builder<T> {
|
||||
|
||||
private T data;
|
||||
|
||||
private String id;
|
||||
|
||||
private String event;
|
||||
@@ -196,7 +187,9 @@ public class ServerSentEvent<T> {
|
||||
|
||||
private String comment;
|
||||
|
||||
public BuilderImpl() {
|
||||
private T data;
|
||||
|
||||
public BuilderImpl() {
|
||||
}
|
||||
|
||||
public BuilderImpl(T data) {
|
||||
@@ -215,12 +208,6 @@ public class ServerSentEvent<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<T> data(T data) {
|
||||
this.data = data;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<T> retry(Duration retry) {
|
||||
this.retry = retry;
|
||||
@@ -233,9 +220,15 @@ public class ServerSentEvent<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<T> data(T data) {
|
||||
this.data = data;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerSentEvent<T> build() {
|
||||
return new ServerSentEvent<T>(this.id, this.event, this.data, this.retry, this.comment);
|
||||
return new ServerSentEvent<T>(this.id, this.event, this.retry, this.comment, this.data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -71,10 +71,10 @@ public class ServerSentEventHttpMessageReader implements HttpMessageReader<Objec
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with JSON {@code Decoder} for decoding to Objects. Support
|
||||
* for decoding to {@code String} event data is built-in.
|
||||
* Constructor with JSON {@code Decoder} for decoding to Objects.
|
||||
* Support for decoding to {@code String} event data is built-in.
|
||||
*/
|
||||
public ServerSentEventHttpMessageReader(Decoder<?> decoder) {
|
||||
public ServerSentEventHttpMessageReader(@Nullable Decoder<?> decoder) {
|
||||
this.decoder = decoder;
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ public class ServerSentEventHttpMessageReader implements HttpMessageReader<Objec
|
||||
/**
|
||||
* Return the configured {@code Decoder}.
|
||||
*/
|
||||
@Nullable
|
||||
public Decoder<?> getDecoder() {
|
||||
return this.decoder;
|
||||
}
|
||||
@@ -93,8 +94,12 @@ public class ServerSentEventHttpMessageReader implements HttpMessageReader<Objec
|
||||
|
||||
@Override
|
||||
public boolean canRead(ResolvableType elementType, @Nullable MediaType mediaType) {
|
||||
return MediaType.TEXT_EVENT_STREAM.includes(mediaType) ||
|
||||
ServerSentEvent.class.isAssignableFrom(elementType.getRawClass());
|
||||
return (MediaType.TEXT_EVENT_STREAM.includes(mediaType) || isServerSentEvent(elementType));
|
||||
}
|
||||
|
||||
private boolean isServerSentEvent(ResolvableType elementType) {
|
||||
Class<?> rawClass = elementType.getRawClass();
|
||||
return (rawClass != null && ServerSentEvent.class.isAssignableFrom(rawClass));
|
||||
}
|
||||
|
||||
|
||||
@@ -102,8 +107,8 @@ public class ServerSentEventHttpMessageReader implements HttpMessageReader<Objec
|
||||
public Flux<Object> read(ResolvableType elementType, ReactiveHttpInputMessage message,
|
||||
Map<String, Object> hints) {
|
||||
|
||||
boolean shouldWrap = ServerSentEvent.class.isAssignableFrom(elementType.getRawClass());
|
||||
ResolvableType valueType = shouldWrap ? elementType.getGeneric(0) : elementType;
|
||||
boolean shouldWrap = isServerSentEvent(elementType);
|
||||
ResolvableType valueType = (shouldWrap ? elementType.getGeneric(0) : elementType);
|
||||
|
||||
return Flux.from(message.getBody())
|
||||
.concatMap(ServerSentEventHttpMessageReader::splitOnNewline)
|
||||
@@ -174,8 +179,7 @@ public class ServerSentEventHttpMessageReader implements HttpMessageReader<Objec
|
||||
}
|
||||
|
||||
private Object decodeData(String data, ResolvableType dataType, Map<String, Object> hints) {
|
||||
|
||||
if (String.class.isAssignableFrom(dataType.getRawClass())) {
|
||||
if (String.class == dataType.resolve()) {
|
||||
return data.substring(0, data.length() - 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.http.codec;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -67,7 +68,7 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Objec
|
||||
* Support for {@code String} event data is built-in.
|
||||
* @param encoder the Encoder to use (may be {@code null})
|
||||
*/
|
||||
public ServerSentEventHttpMessageWriter(Encoder<?> encoder) {
|
||||
public ServerSentEventHttpMessageWriter(@Nullable Encoder<?> encoder) {
|
||||
this.encoder = encoder;
|
||||
}
|
||||
|
||||
@@ -103,7 +104,8 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Objec
|
||||
private Flux<Publisher<DataBuffer>> encode(Publisher<?> input, DataBufferFactory factory,
|
||||
ResolvableType elementType, Map<String, Object> hints) {
|
||||
|
||||
ResolvableType valueType = (ServerSentEvent.class.isAssignableFrom(elementType.getRawClass()) ?
|
||||
Class<?> elementClass = elementType.getRawClass();
|
||||
ResolvableType valueType = (elementClass != null && ServerSentEvent.class.isAssignableFrom(elementClass) ?
|
||||
elementType.getGeneric() : elementType);
|
||||
|
||||
return Flux.from(input).map(element -> {
|
||||
@@ -112,24 +114,29 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Objec
|
||||
(ServerSentEvent<?>) element : ServerSentEvent.builder().data(element).build());
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (sse.id() != null) {
|
||||
writeField("id", sse.id(), sb);
|
||||
String id = sse.id();
|
||||
String event = sse.event();
|
||||
Duration retry = sse.retry();
|
||||
String comment = sse.comment();
|
||||
Object data = sse.data();
|
||||
if (id != null) {
|
||||
writeField("id", id, sb);
|
||||
}
|
||||
if (sse.event() != null) {
|
||||
writeField("event", sse.event(), sb);
|
||||
if (event != null) {
|
||||
writeField("event", event, sb);
|
||||
}
|
||||
if (sse.retry() != null) {
|
||||
writeField("retry", sse.retry().toMillis(), sb);
|
||||
if (retry != null) {
|
||||
writeField("retry", retry.toMillis(), sb);
|
||||
}
|
||||
if (sse.comment() != null) {
|
||||
sb.append(':').append(sse.comment().replaceAll("\\n", "\n:")).append("\n");
|
||||
if (comment != null) {
|
||||
sb.append(':').append(comment.replaceAll("\\n", "\n:")).append("\n");
|
||||
}
|
||||
if (sse.data() != null) {
|
||||
if (data != null) {
|
||||
sb.append("data:");
|
||||
}
|
||||
|
||||
return Flux.concat(encodeText(sb, factory),
|
||||
encodeData(sse.data(), valueType, factory, hints),
|
||||
encodeData(data, valueType, factory, hints),
|
||||
encodeText("\n", factory));
|
||||
});
|
||||
}
|
||||
@@ -142,7 +149,7 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Objec
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> Flux<DataBuffer> encodeData(T data, ResolvableType valueType,
|
||||
private <T> Flux<DataBuffer> encodeData(@Nullable T data, ResolvableType valueType,
|
||||
DataBufferFactory factory, Map<String, Object> hints) {
|
||||
|
||||
if (data == null) {
|
||||
@@ -170,7 +177,7 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Objec
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> write(Publisher<?> input, @Nullable ResolvableType actualType, ResolvableType elementType,
|
||||
public Mono<Void> write(Publisher<?> input, ResolvableType actualType, ResolvableType elementType,
|
||||
@Nullable MediaType mediaType, ServerHttpRequest request, ServerHttpResponse response,
|
||||
Map<String, Object> hints) {
|
||||
|
||||
@@ -182,7 +189,7 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Objec
|
||||
}
|
||||
|
||||
private Map<String, Object> getEncodeHints(ResolvableType actualType, ResolvableType elementType,
|
||||
MediaType mediaType, ServerHttpRequest request, ServerHttpResponse response) {
|
||||
@Nullable MediaType mediaType, ServerHttpRequest request, ServerHttpResponse response) {
|
||||
|
||||
if (this.encoder instanceof HttpMessageEncoder) {
|
||||
HttpMessageEncoder<?> httpEncoder = (HttpMessageEncoder<?>) this.encoder;
|
||||
|
||||
@@ -77,7 +77,7 @@ public abstract class Jackson2CodecSupport {
|
||||
}
|
||||
|
||||
|
||||
protected boolean supportsMimeType(MimeType mimeType) {
|
||||
protected boolean supportsMimeType(@Nullable MimeType mimeType) {
|
||||
return (mimeType == null || this.mimeTypes.stream().anyMatch(m -> m.isCompatibleWith(mimeType)));
|
||||
}
|
||||
|
||||
@@ -86,8 +86,8 @@ public abstract class Jackson2CodecSupport {
|
||||
return typeFactory.constructType(GenericTypeResolver.resolveType(type, contextClass));
|
||||
}
|
||||
|
||||
protected Map<String, Object> getHints(ResolvableType actualType) {
|
||||
return getParameter(actualType)
|
||||
protected Map<String, Object> getHints(ResolvableType resolvableType) {
|
||||
return getParameter(resolvableType)
|
||||
.flatMap(parameter -> Optional.ofNullable(getAnnotation(parameter, JsonView.class))
|
||||
.map(annotation -> {
|
||||
Class<?>[] classes = annotation.value();
|
||||
@@ -102,6 +102,7 @@ public abstract class Jackson2CodecSupport {
|
||||
(MethodParameter) type.getSource() : null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected abstract <A extends Annotation> A getAnnotation(MethodParameter parameter, Class<A> annotType);
|
||||
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ public class Jackson2JsonDecoder extends Jackson2CodecSupport implements HttpMes
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<Object> decode(Publisher<DataBuffer> input, @Nullable ResolvableType elementType,
|
||||
public Flux<Object> decode(Publisher<DataBuffer> input, ResolvableType elementType,
|
||||
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
|
||||
|
||||
return decodeInternal(this.fluxDecoder, input, elementType, mimeType, hints);
|
||||
@@ -97,14 +97,14 @@ public class Jackson2JsonDecoder extends Jackson2CodecSupport implements HttpMes
|
||||
}
|
||||
|
||||
private Flux<Object> decodeInternal(JsonObjectDecoder objectDecoder, Publisher<DataBuffer> inputStream,
|
||||
ResolvableType elementType, MimeType mimeType, Map<String, Object> hints) {
|
||||
ResolvableType elementType, @Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
|
||||
|
||||
Assert.notNull(inputStream, "'inputStream' must not be null");
|
||||
Assert.notNull(elementType, "'elementType' must not be null");
|
||||
|
||||
Class<?> contextClass = getParameter(elementType).map(MethodParameter::getContainingClass).orElse(null);
|
||||
JavaType javaType = getJavaType(elementType.getType(), contextClass);
|
||||
Class<?> jsonView = (Class<?>) hints.get(Jackson2CodecSupport.JSON_VIEW_HINT);
|
||||
Class<?> jsonView = (hints != null ? (Class<?>) hints.get(Jackson2CodecSupport.JSON_VIEW_HINT) : null);
|
||||
|
||||
ObjectReader reader = (jsonView != null ?
|
||||
this.objectMapper.readerWithView(jsonView).forType(javaType) :
|
||||
|
||||
@@ -139,8 +139,8 @@ public class Jackson2JsonEncoder extends Jackson2CodecSupport implements HttpMes
|
||||
}
|
||||
}
|
||||
|
||||
private DataBuffer encodeValue(Object value, MimeType mimeType, DataBufferFactory bufferFactory,
|
||||
ResolvableType elementType, Map<String, Object> hints) {
|
||||
private DataBuffer encodeValue(Object value, @Nullable MimeType mimeType, DataBufferFactory bufferFactory,
|
||||
ResolvableType elementType, @Nullable Map<String, Object> hints) {
|
||||
|
||||
TypeFactory typeFactory = this.objectMapper.getTypeFactory();
|
||||
JavaType javaType = typeFactory.constructType(elementType.getType());
|
||||
@@ -148,7 +148,7 @@ public class Jackson2JsonEncoder extends Jackson2CodecSupport implements HttpMes
|
||||
javaType = getJavaType(elementType.getType(), null);
|
||||
}
|
||||
|
||||
Class<?> jsonView = (Class<?>) hints.get(Jackson2CodecSupport.JSON_VIEW_HINT);
|
||||
Class<?> jsonView = (hints != null ? (Class<?>) hints.get(Jackson2CodecSupport.JSON_VIEW_HINT) : null);
|
||||
ObjectWriter writer = (jsonView != null ?
|
||||
this.objectMapper.writerWithView(jsonView) : this.objectMapper.writer());
|
||||
|
||||
@@ -189,10 +189,10 @@ public class Jackson2JsonEncoder extends Jackson2CodecSupport implements HttpMes
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getEncodeHints(ResolvableType actualType, ResolvableType elementType,
|
||||
MediaType mediaType, ServerHttpRequest request, ServerHttpResponse response) {
|
||||
public Map<String, Object> getEncodeHints(@Nullable ResolvableType actualType, ResolvableType elementType,
|
||||
@Nullable MediaType mediaType, ServerHttpRequest request, ServerHttpResponse response) {
|
||||
|
||||
return getHints(actualType);
|
||||
return (actualType != null ? getHints(actualType) : Collections.emptyMap());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -147,9 +147,7 @@ class JsonObjectDecoder extends AbstractDecoder<DataBuffer> {
|
||||
if (this.openBraces == 0) {
|
||||
ByteBuf json = extractObject(this.input, this.input.readerIndex(),
|
||||
this.index + 1 - this.input.readerIndex());
|
||||
if (json != null) {
|
||||
chunks.add(dataBufferFactory.wrap(json.nioBuffer()));
|
||||
}
|
||||
chunks.add(dataBufferFactory.wrap(json.nioBuffer()));
|
||||
|
||||
// The JSON object/array was extracted => discard the bytes from
|
||||
// the input buffer.
|
||||
@@ -174,16 +172,12 @@ class JsonObjectDecoder extends AbstractDecoder<DataBuffer> {
|
||||
int idxNoSpaces = this.index - 1;
|
||||
while (idxNoSpaces >= this.input.readerIndex() &&
|
||||
Character.isWhitespace(this.input.getByte(idxNoSpaces))) {
|
||||
|
||||
idxNoSpaces--;
|
||||
}
|
||||
|
||||
ByteBuf json = extractObject(this.input, this.input.readerIndex(),
|
||||
idxNoSpaces + 1 - this.input.readerIndex());
|
||||
|
||||
if (json != null) {
|
||||
chunks.add(dataBufferFactory.wrap(json.nioBuffer()));
|
||||
}
|
||||
chunks.add(dataBufferFactory.wrap(json.nioBuffer()));
|
||||
|
||||
this.input.readerIndex(this.index + 1);
|
||||
|
||||
|
||||
@@ -111,8 +111,9 @@ public class MultipartHttpMessageWriter implements HttpMessageWriter<MultiValueM
|
||||
|
||||
@Override
|
||||
public boolean canWrite(ResolvableType elementType, @Nullable MediaType mediaType) {
|
||||
return MultiValueMap.class.isAssignableFrom(elementType.getRawClass()) &&
|
||||
(mediaType == null || MediaType.MULTIPART_FORM_DATA.isCompatibleWith(mediaType));
|
||||
Class<?> rawClass = elementType.getRawClass();
|
||||
return (rawClass != null && MultiValueMap.class.isAssignableFrom(rawClass) &&
|
||||
(mediaType == null || MediaType.MULTIPART_FORM_DATA.isCompatibleWith(mediaType)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -156,6 +157,7 @@ public class MultipartHttpMessageWriter implements HttpMessageWriter<MultiValueM
|
||||
if (value instanceof HttpEntity) {
|
||||
outputMessage.getHeaders().putAll(((HttpEntity<T>) value).getHeaders());
|
||||
body = ((HttpEntity<T>) value).getBody();
|
||||
Assert.state(body != null, "MultipartHttpMessageWriter only supports HttpEntity with body");
|
||||
}
|
||||
else {
|
||||
body = value;
|
||||
|
||||
@@ -112,18 +112,17 @@ public class SynchronossPartHttpMessageReader implements HttpMessageReader<Part>
|
||||
|
||||
private final DataBufferFactory bufferFactory;
|
||||
|
||||
|
||||
SynchronossPartGenerator(ReactiveHttpInputMessage inputMessage, DataBufferFactory factory) {
|
||||
this.inputMessage = inputMessage;
|
||||
this.bufferFactory = factory;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void accept(FluxSink<Part> emitter) {
|
||||
|
||||
HttpHeaders headers = this.inputMessage.getHeaders();
|
||||
MediaType mediaType = headers.getContentType();
|
||||
Assert.state(mediaType != null, "No content type set");
|
||||
|
||||
int length = Math.toIntExact(headers.getContentLength());
|
||||
Charset charset = Optional.ofNullable(mediaType.getCharset()).orElse(StandardCharsets.UTF_8);
|
||||
MultipartContext context = new MultipartContext(mediaType.toString(), length, charset.name());
|
||||
@@ -159,6 +158,8 @@ public class SynchronossPartHttpMessageReader implements HttpMessageReader<Part>
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Listen for parser output and adapt to {@code Flux<Sink<Part>>}.
|
||||
*/
|
||||
@@ -172,14 +173,12 @@ public class SynchronossPartHttpMessageReader implements HttpMessageReader<Part>
|
||||
|
||||
private final AtomicInteger terminated = new AtomicInteger(0);
|
||||
|
||||
|
||||
FluxSinkAdapterListener(FluxSink<Part> sink, DataBufferFactory bufferFactory, MultipartContext context) {
|
||||
this.sink = sink;
|
||||
this.bufferFactory = bufferFactory;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onPartFinished(StreamStorage storage, Map<String, List<String>> headers) {
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
@@ -238,7 +237,6 @@ public class SynchronossPartHttpMessageReader implements HttpMessageReader<Part>
|
||||
|
||||
private final DataBufferFactory bufferFactory;
|
||||
|
||||
|
||||
AbstractSynchronossPart(HttpHeaders headers, DataBufferFactory bufferFactory) {
|
||||
Assert.notNull(headers, "HttpHeaders is required");
|
||||
Assert.notNull(bufferFactory, "'bufferFactory' is required");
|
||||
@@ -246,7 +244,6 @@ public class SynchronossPartHttpMessageReader implements HttpMessageReader<Part>
|
||||
this.bufferFactory = bufferFactory;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return MultipartUtils.getFieldName(this.headers);
|
||||
@@ -262,18 +259,17 @@ public class SynchronossPartHttpMessageReader implements HttpMessageReader<Part>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class DefaultSynchronossPart extends AbstractSynchronossPart {
|
||||
|
||||
private final StreamStorage storage;
|
||||
|
||||
|
||||
DefaultSynchronossPart(HttpHeaders headers, StreamStorage storage, DataBufferFactory factory) {
|
||||
super(headers, factory);
|
||||
Assert.notNull(storage, "'storage' is required");
|
||||
this.storage = storage;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Flux<DataBuffer> content() {
|
||||
InputStream inputStream = this.storage.getInputStream();
|
||||
@@ -285,8 +281,8 @@ public class SynchronossPartHttpMessageReader implements HttpMessageReader<Part>
|
||||
}
|
||||
}
|
||||
|
||||
private static class SynchronossFilePart extends DefaultSynchronossPart implements FilePart {
|
||||
|
||||
private static class SynchronossFilePart extends DefaultSynchronossPart implements FilePart {
|
||||
|
||||
public SynchronossFilePart(HttpHeaders headers, StreamStorage storage,
|
||||
String fileName, DataBufferFactory factory) {
|
||||
@@ -294,7 +290,6 @@ public class SynchronossPartHttpMessageReader implements HttpMessageReader<Part>
|
||||
super(headers, storage, factory);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String filename() {
|
||||
return MultipartUtils.getFileName(headers());
|
||||
@@ -341,17 +336,16 @@ public class SynchronossPartHttpMessageReader implements HttpMessageReader<Part>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class SynchronossFormFieldPart extends AbstractSynchronossPart implements FormFieldPart {
|
||||
|
||||
private final String content;
|
||||
|
||||
|
||||
SynchronossFormFieldPart(HttpHeaders headers, DataBufferFactory bufferFactory, String content) {
|
||||
super(headers, bufferFactory);
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String value() {
|
||||
return this.content;
|
||||
|
||||
@@ -42,6 +42,7 @@ import org.springframework.core.codec.CodecException;
|
||||
import org.springframework.core.codec.DecodingException;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.MimeType;
|
||||
import org.springframework.util.MimeTypeUtils;
|
||||
@@ -82,8 +83,8 @@ public class Jaxb2XmlDecoder extends AbstractDecoder<Object> {
|
||||
public boolean canDecode(ResolvableType elementType, @Nullable MimeType mimeType) {
|
||||
if (super.canDecode(elementType, mimeType)) {
|
||||
Class<?> outputClass = elementType.getRawClass();
|
||||
return outputClass.isAnnotationPresent(XmlRootElement.class) ||
|
||||
outputClass.isAnnotationPresent(XmlType.class);
|
||||
return (outputClass != null && (outputClass.isAnnotationPresent(XmlRootElement.class) ||
|
||||
outputClass.isAnnotationPresent(XmlType.class)));
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
@@ -91,11 +92,14 @@ public class Jaxb2XmlDecoder extends AbstractDecoder<Object> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<Object> decode(Publisher<DataBuffer> inputStream, @Nullable ResolvableType elementType,
|
||||
public Flux<Object> decode(Publisher<DataBuffer> inputStream, ResolvableType elementType,
|
||||
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
|
||||
|
||||
Class<?> outputClass = elementType.getRawClass();
|
||||
Flux<XMLEvent> xmlEventFlux = this.xmlEventDecoder.decode(inputStream, null, mimeType, hints);
|
||||
Assert.state(outputClass != null, "Unresolvable output class");
|
||||
|
||||
Flux<XMLEvent> xmlEventFlux = this.xmlEventDecoder.decode(
|
||||
inputStream, ResolvableType.forClass(XMLEvent.class), mimeType, hints);
|
||||
|
||||
QName typeName = toQName(outputClass);
|
||||
Flux<List<XMLEvent>> splitEvents = split(xmlEventFlux, typeName);
|
||||
|
||||
@@ -71,7 +71,7 @@ public class Jaxb2XmlEncoder extends AbstractSingleValueEncoder<Object> {
|
||||
|
||||
@Override
|
||||
protected Flux<DataBuffer> encode(Object value, DataBufferFactory dataBufferFactory,
|
||||
ResolvableType type, MimeType mimeType, Map<String, Object> hints) {
|
||||
ResolvableType type, MimeType mimeType, @Nullable Map<String, Object> hints) {
|
||||
try {
|
||||
DataBuffer buffer = dataBufferFactory.allocateBuffer(1024);
|
||||
OutputStream outputStream = buffer.asOutputStream();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -90,7 +90,7 @@ public class XmlEventDecoder extends AbstractDecoder<XMLEvent> {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Flux<XMLEvent> decode(Publisher<DataBuffer> inputStream, @Nullable ResolvableType elementType,
|
||||
public Flux<XMLEvent> decode(Publisher<DataBuffer> inputStream, ResolvableType elementType,
|
||||
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
|
||||
|
||||
Flux<DataBuffer> flux = Flux.from(inputStream);
|
||||
|
||||
@@ -71,7 +71,7 @@ public abstract class AbstractGenericHttpMessageConverter<T> extends AbstractHtt
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canWrite(@Nullable Type type, @Nullable Class<?> clazz, @Nullable MediaType mediaType) {
|
||||
public boolean canWrite(@Nullable Type type, Class<?> clazz, @Nullable MediaType mediaType) {
|
||||
return canWrite(clazz, mediaType);
|
||||
}
|
||||
|
||||
|
||||
@@ -191,7 +191,7 @@ public abstract class AbstractHttpMessageConverter<T> implements HttpMessageConv
|
||||
* Future implementations might add some default behavior, however.
|
||||
*/
|
||||
@Override
|
||||
public final T read(@Nullable Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException {
|
||||
public final T read(Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException {
|
||||
return readInternal(clazz, inputMessage);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -132,7 +132,7 @@ public class BufferedImageHttpMessageConverter implements HttpMessageConverter<B
|
||||
return (BufferedImage.class == clazz && isReadable(mediaType));
|
||||
}
|
||||
|
||||
private boolean isReadable(MediaType mediaType) {
|
||||
private boolean isReadable(@Nullable MediaType mediaType) {
|
||||
if (mediaType == null) {
|
||||
return true;
|
||||
}
|
||||
@@ -145,7 +145,7 @@ public class BufferedImageHttpMessageConverter implements HttpMessageConverter<B
|
||||
return (BufferedImage.class == clazz && isWritable(mediaType));
|
||||
}
|
||||
|
||||
private boolean isWritable(MediaType mediaType) {
|
||||
private boolean isWritable(@Nullable MediaType mediaType) {
|
||||
if (mediaType == null || MediaType.ALL.equals(mediaType)) {
|
||||
return true;
|
||||
}
|
||||
@@ -167,6 +167,9 @@ public class BufferedImageHttpMessageConverter implements HttpMessageConverter<B
|
||||
try {
|
||||
imageInputStream = createImageInputStream(inputMessage.getBody());
|
||||
MediaType contentType = inputMessage.getHeaders().getContentType();
|
||||
if (contentType == null) {
|
||||
throw new HttpMessageNotReadableException("No Content-Type header");
|
||||
}
|
||||
Iterator<ImageReader> imageReaders = ImageIO.getImageReadersByMIMEType(contentType.toString());
|
||||
if (imageReaders.hasNext()) {
|
||||
imageReader = imageReaders.next();
|
||||
@@ -226,7 +229,7 @@ public class BufferedImageHttpMessageConverter implements HttpMessageConverter<B
|
||||
}
|
||||
}
|
||||
|
||||
private MediaType getContentType(MediaType contentType) {
|
||||
private MediaType getContentType(@Nullable MediaType contentType) {
|
||||
if (contentType == null || contentType.isWildcardType() || contentType.isWildcardSubtype()) {
|
||||
contentType = getDefaultContentType();
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.mail.internet.MimeUtility;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
@@ -151,19 +150,16 @@ public class FormHttpMessageConverter implements HttpMessageConverter<MultiValue
|
||||
/**
|
||||
* Set the default character set to use for reading and writing form data when
|
||||
* the request or response Content-Type header does not explicitly specify it.
|
||||
*
|
||||
* <p>As of 4.3, this is also used as the default charset for the conversion
|
||||
* of text bodies in a multipart request.
|
||||
*
|
||||
* <p>As of 5.0 this is also used for part headers including
|
||||
* "Content-Disposition" (and its filename parameter) unless (the mutually
|
||||
* exclusive) {@link #setMultipartCharset} is also set, in which case part
|
||||
* headers are encoded as ASCII and <i>filename</i> is encoded with the
|
||||
* "encoded-word" syntax from RFC 2047.
|
||||
*
|
||||
* <p>By default this is set to "UTF-8".
|
||||
*/
|
||||
public void setCharset(Charset charset) {
|
||||
public void setCharset(@Nullable Charset charset) {
|
||||
if (charset != this.charset) {
|
||||
this.charset = (charset != null ? charset : DEFAULT_CHARSET);
|
||||
applyDefaultCharset();
|
||||
@@ -240,7 +236,8 @@ public class FormHttpMessageConverter implements HttpMessageConverter<MultiValue
|
||||
HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
|
||||
|
||||
MediaType contentType = inputMessage.getHeaders().getContentType();
|
||||
Charset charset = (contentType.getCharset() != null ? contentType.getCharset() : this.charset);
|
||||
Charset charset = (contentType != null && contentType.getCharset() != null ?
|
||||
contentType.getCharset() : this.charset);
|
||||
String body = StreamUtils.copyToString(inputMessage.getBody(), charset);
|
||||
|
||||
String[] pairs = StringUtils.tokenizeToStringArray(body, "&");
|
||||
@@ -273,7 +270,7 @@ public class FormHttpMessageConverter implements HttpMessageConverter<MultiValue
|
||||
}
|
||||
|
||||
|
||||
private boolean isMultipart(MultiValueMap<String, ?> map, MediaType contentType) {
|
||||
private boolean isMultipart(MultiValueMap<String, ?> map, @Nullable MediaType contentType) {
|
||||
if (contentType != null) {
|
||||
return MediaType.MULTIPART_FORM_DATA.includes(contentType);
|
||||
}
|
||||
@@ -287,7 +284,7 @@ public class FormHttpMessageConverter implements HttpMessageConverter<MultiValue
|
||||
return false;
|
||||
}
|
||||
|
||||
private void writeForm(MultiValueMap<String, String> form, MediaType contentType,
|
||||
private void writeForm(MultiValueMap<String, String> form, @Nullable MediaType contentType,
|
||||
HttpOutputMessage outputMessage) throws IOException {
|
||||
|
||||
Charset charset;
|
||||
@@ -387,6 +384,9 @@ public class FormHttpMessageConverter implements HttpMessageConverter<MultiValue
|
||||
@SuppressWarnings("unchecked")
|
||||
private void writePart(String name, HttpEntity<?> partEntity, OutputStream os) throws IOException {
|
||||
Object partBody = partEntity.getBody();
|
||||
if (partBody == null) {
|
||||
throw new IllegalStateException("Empty body for part '" + name + "': " + partEntity);
|
||||
}
|
||||
Class<?> partType = partBody.getClass();
|
||||
HttpHeaders partHeaders = partEntity.getHeaders();
|
||||
MediaType partContentType = partHeaders.getContentType();
|
||||
|
||||
@@ -79,7 +79,7 @@ public interface GenericHttpMessageConverter<T> extends HttpMessageConverter<T>
|
||||
* @return {@code true} if writable; {@code false} otherwise
|
||||
* @since 4.2
|
||||
*/
|
||||
boolean canWrite(@Nullable Type type, @Nullable Class<?> clazz, @Nullable MediaType mediaType);
|
||||
boolean canWrite(@Nullable Type type, Class<?> clazz, @Nullable MediaType mediaType);
|
||||
|
||||
/**
|
||||
* Write an given object to the given output message.
|
||||
|
||||
@@ -66,7 +66,7 @@ public interface HttpMessageConverter<T> {
|
||||
* @throws IOException in case of I/O errors
|
||||
* @throws HttpMessageNotReadableException in case of conversion errors
|
||||
*/
|
||||
T read(@Nullable Class<? extends T> clazz, HttpInputMessage inputMessage)
|
||||
T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
|
||||
throws IOException, HttpMessageNotReadableException;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -91,12 +91,12 @@ public class ObjectToStringHttpMessageConverter extends AbstractHttpMessageConve
|
||||
|
||||
@Override
|
||||
public boolean canRead(Class<?> clazz, @Nullable MediaType mediaType) {
|
||||
return this.conversionService.canConvert(String.class, clazz) && canRead(mediaType);
|
||||
return canRead(mediaType) && this.conversionService.canConvert(String.class, clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType) {
|
||||
return this.conversionService.canConvert(clazz, String.class) && canWrite(mediaType);
|
||||
return canWrite(mediaType) && this.conversionService.canConvert(clazz, String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -108,18 +108,28 @@ public class ObjectToStringHttpMessageConverter extends AbstractHttpMessageConve
|
||||
@Override
|
||||
protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage) throws IOException {
|
||||
String value = this.stringHttpMessageConverter.readInternal(String.class, inputMessage);
|
||||
return this.conversionService.convert(value, clazz);
|
||||
Object result = this.conversionService.convert(value, clazz);
|
||||
if (result == null) {
|
||||
throw new HttpMessageConversionException(
|
||||
"Unexpected null conversion result for '" + value + "' to " + clazz);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeInternal(Object obj, HttpOutputMessage outputMessage) throws IOException {
|
||||
String value = this.conversionService.convert(obj, String.class);
|
||||
this.stringHttpMessageConverter.writeInternal(value, outputMessage);
|
||||
if (value != null) {
|
||||
this.stringHttpMessageConverter.writeInternal(value, outputMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Long getContentLength(Object obj, @Nullable MediaType contentType) {
|
||||
String value = this.conversionService.convert(obj, String.class);
|
||||
if (value == null) {
|
||||
return 0L;
|
||||
}
|
||||
return this.stringHttpMessageConverter.getContentLength(value, contentType);
|
||||
}
|
||||
|
||||
|
||||
@@ -78,12 +78,11 @@ public class ResourceHttpMessageConverter extends AbstractHttpMessageConverter<R
|
||||
protected Resource readInternal(Class<? extends Resource> clazz, HttpInputMessage inputMessage)
|
||||
throws IOException, HttpMessageNotReadableException {
|
||||
|
||||
final String filename = inputMessage.getHeaders().getContentDisposition().getFilename();
|
||||
if (this.supportsReadStreaming && InputStreamResource.class == clazz) {
|
||||
return new InputStreamResource(inputMessage.getBody()) {
|
||||
@Override
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
return inputMessage.getHeaders().getContentDisposition().getFilename();
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -92,7 +91,7 @@ public class ResourceHttpMessageConverter extends AbstractHttpMessageConverter<R
|
||||
return new ByteArrayResource(body) {
|
||||
@Override
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
return inputMessage.getHeaders().getContentDisposition().getFilename();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -99,8 +99,9 @@ public class ResourceRegionHttpMessageConverter extends AbstractGenericHttpMessa
|
||||
@Override
|
||||
public boolean canWrite(@Nullable Type type, @Nullable Class<?> clazz, @Nullable MediaType mediaType) {
|
||||
if (!(type instanceof ParameterizedType)) {
|
||||
return ResourceRegion.class.isAssignableFrom((Class<?>) type);
|
||||
return (type instanceof Class && ResourceRegion.class.isAssignableFrom((Class<?>) type));
|
||||
}
|
||||
|
||||
ParameterizedType parameterizedType = (ParameterizedType) type;
|
||||
if (!(parameterizedType.getRawType() instanceof Class)) {
|
||||
return false;
|
||||
@@ -116,6 +117,7 @@ public class ResourceRegionHttpMessageConverter extends AbstractGenericHttpMessa
|
||||
if (!(typeArgument instanceof Class)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Class<?> typeArgumentClass = (Class<?>) typeArgument;
|
||||
return typeArgumentClass.isAssignableFrom(ResourceRegion.class);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.http.HttpOutputMessage;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
/**
|
||||
@@ -116,12 +117,14 @@ public class StringHttpMessageConverter extends AbstractHttpMessageConverter<Str
|
||||
return this.availableCharsets;
|
||||
}
|
||||
|
||||
private Charset getContentTypeCharset(MediaType contentType) {
|
||||
private Charset getContentTypeCharset(@Nullable MediaType contentType) {
|
||||
if (contentType != null && contentType.getCharset() != null) {
|
||||
return contentType.getCharset();
|
||||
}
|
||||
else {
|
||||
return getDefaultCharset();
|
||||
Charset charset = getDefaultCharset();
|
||||
Assert.state(charset != null, "No default charset");
|
||||
return charset;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -190,7 +190,7 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractGener
|
||||
* (typically a {@link JsonMappingException})
|
||||
* @since 4.3
|
||||
*/
|
||||
protected void logWarningIfNecessary(Type type, Throwable cause) {
|
||||
protected void logWarningIfNecessary(Type type, @Nullable Throwable cause) {
|
||||
if (cause != null && !(cause instanceof JsonMappingException && cause.getMessage().startsWith("Can not find"))) {
|
||||
String msg = "Failed to evaluate Jackson " + (type instanceof JavaType ? "de" : "") +
|
||||
"serialization for type [" + type + "]";
|
||||
@@ -258,7 +258,7 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractGener
|
||||
serializationView = container.getSerializationView();
|
||||
filters = container.getFilters();
|
||||
}
|
||||
if (type != null && value != null && TypeUtils.isAssignable(type, value.getClass())) {
|
||||
if (type != null && TypeUtils.isAssignable(type, value.getClass())) {
|
||||
javaType = getJavaType(type, null);
|
||||
}
|
||||
ObjectWriter objectWriter;
|
||||
@@ -326,7 +326,7 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractGener
|
||||
* @param contentType the media type as requested by the caller
|
||||
* @return the JSON encoding to use (never {@code null})
|
||||
*/
|
||||
protected JsonEncoding getJsonEncoding(MediaType contentType) {
|
||||
protected JsonEncoding getJsonEncoding(@Nullable MediaType contentType) {
|
||||
if (contentType != null && contentType.getCharset() != null) {
|
||||
Charset charset = contentType.getCharset();
|
||||
for (JsonEncoding encoding : JsonEncoding.values()) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -276,9 +276,7 @@ public class Jackson2ObjectMapperBuilder {
|
||||
* @see com.fasterxml.jackson.databind.ObjectMapper#addMixInAnnotations(Class, Class)
|
||||
*/
|
||||
public Jackson2ObjectMapperBuilder mixIn(Class<?> target, Class<?> mixinSource) {
|
||||
if (mixinSource != null) {
|
||||
this.mixIns.put(target, mixinSource);
|
||||
}
|
||||
this.mixIns.put(target, mixinSource);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -291,9 +289,7 @@ public class Jackson2ObjectMapperBuilder {
|
||||
* @see com.fasterxml.jackson.databind.ObjectMapper#addMixInAnnotations(Class, Class)
|
||||
*/
|
||||
public Jackson2ObjectMapperBuilder mixIns(Map<Class<?>, Class<?>> mixIns) {
|
||||
if (mixIns != null) {
|
||||
this.mixIns.putAll(mixIns);
|
||||
}
|
||||
this.mixIns.putAll(mixIns);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -303,14 +299,12 @@ public class Jackson2ObjectMapperBuilder {
|
||||
* @see #serializersByType(Map)
|
||||
*/
|
||||
public Jackson2ObjectMapperBuilder serializers(JsonSerializer<?>... serializers) {
|
||||
if (serializers != null) {
|
||||
for (JsonSerializer<?> serializer : serializers) {
|
||||
Class<?> handledType = serializer.handledType();
|
||||
if (handledType == null || handledType == Object.class) {
|
||||
throw new IllegalArgumentException("Unknown handled type in " + serializer.getClass().getName());
|
||||
}
|
||||
this.serializers.put(serializer.handledType(), serializer);
|
||||
for (JsonSerializer<?> serializer : serializers) {
|
||||
Class<?> handledType = serializer.handledType();
|
||||
if (handledType == null || handledType == Object.class) {
|
||||
throw new IllegalArgumentException("Unknown handled type in " + serializer.getClass().getName());
|
||||
}
|
||||
this.serializers.put(serializer.handledType(), serializer);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
@@ -321,9 +315,7 @@ public class Jackson2ObjectMapperBuilder {
|
||||
* @since 4.1.2
|
||||
*/
|
||||
public Jackson2ObjectMapperBuilder serializerByType(Class<?> type, JsonSerializer<?> serializer) {
|
||||
if (serializer != null) {
|
||||
this.serializers.put(type, serializer);
|
||||
}
|
||||
this.serializers.put(type, serializer);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -332,9 +324,7 @@ public class Jackson2ObjectMapperBuilder {
|
||||
* @see #serializers(JsonSerializer...)
|
||||
*/
|
||||
public Jackson2ObjectMapperBuilder serializersByType(Map<Class<?>, JsonSerializer<?>> serializers) {
|
||||
if (serializers != null) {
|
||||
this.serializers.putAll(serializers);
|
||||
}
|
||||
this.serializers.putAll(serializers);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -345,14 +335,12 @@ public class Jackson2ObjectMapperBuilder {
|
||||
* @see #deserializersByType(Map)
|
||||
*/
|
||||
public Jackson2ObjectMapperBuilder deserializers(JsonDeserializer<?>... deserializers) {
|
||||
if (deserializers != null) {
|
||||
for (JsonDeserializer<?> deserializer : deserializers) {
|
||||
Class<?> handledType = deserializer.handledType();
|
||||
if (handledType == null || handledType == Object.class) {
|
||||
throw new IllegalArgumentException("Unknown handled type in " + deserializer.getClass().getName());
|
||||
}
|
||||
this.deserializers.put(deserializer.handledType(), deserializer);
|
||||
for (JsonDeserializer<?> deserializer : deserializers) {
|
||||
Class<?> handledType = deserializer.handledType();
|
||||
if (handledType == null || handledType == Object.class) {
|
||||
throw new IllegalArgumentException("Unknown handled type in " + deserializer.getClass().getName());
|
||||
}
|
||||
this.deserializers.put(deserializer.handledType(), deserializer);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
@@ -362,9 +350,7 @@ public class Jackson2ObjectMapperBuilder {
|
||||
* @since 4.1.2
|
||||
*/
|
||||
public Jackson2ObjectMapperBuilder deserializerByType(Class<?> type, JsonDeserializer<?> deserializer) {
|
||||
if (deserializer != null) {
|
||||
this.deserializers.put(type, deserializer);
|
||||
}
|
||||
this.deserializers.put(type, deserializer);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -372,9 +358,7 @@ public class Jackson2ObjectMapperBuilder {
|
||||
* Configure custom deserializers for the given types.
|
||||
*/
|
||||
public Jackson2ObjectMapperBuilder deserializersByType(Map<Class<?>, JsonDeserializer<?>> deserializers) {
|
||||
if (deserializers != null) {
|
||||
this.deserializers.putAll(deserializers);
|
||||
}
|
||||
this.deserializers.putAll(deserializers);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -449,10 +433,8 @@ public class Jackson2ObjectMapperBuilder {
|
||||
* @see com.fasterxml.jackson.databind.MapperFeature
|
||||
*/
|
||||
public Jackson2ObjectMapperBuilder featuresToEnable(Object... featuresToEnable) {
|
||||
if (featuresToEnable != null) {
|
||||
for (Object feature : featuresToEnable) {
|
||||
this.features.put(feature, Boolean.TRUE);
|
||||
}
|
||||
for (Object feature : featuresToEnable) {
|
||||
this.features.put(feature, Boolean.TRUE);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
@@ -466,10 +448,8 @@ public class Jackson2ObjectMapperBuilder {
|
||||
* @see com.fasterxml.jackson.databind.MapperFeature
|
||||
*/
|
||||
public Jackson2ObjectMapperBuilder featuresToDisable(Object... featuresToDisable) {
|
||||
if (featuresToDisable != null) {
|
||||
for (Object feature : featuresToDisable) {
|
||||
this.features.put(feature, Boolean.FALSE);
|
||||
}
|
||||
for (Object feature : featuresToDisable) {
|
||||
this.features.put(feature, Boolean.FALSE);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -422,7 +422,7 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(@Nullable ClassLoader beanClassLoader) {
|
||||
public void setBeanClassLoader(ClassLoader beanClassLoader) {
|
||||
this.builder.moduleClassLoader(beanClassLoader);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 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,6 +21,7 @@ import java.io.InputStream;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* {@link HttpInputMessage} that can eventually stores a Jackson view that will be used
|
||||
@@ -38,12 +39,12 @@ public class MappingJacksonInputMessage implements HttpInputMessage {
|
||||
private Class<?> deserializationView;
|
||||
|
||||
|
||||
public MappingJacksonInputMessage(InputStream body, HttpHeaders headers) {
|
||||
public MappingJacksonInputMessage(@Nullable InputStream body, HttpHeaders headers) {
|
||||
this.body = body;
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
public MappingJacksonInputMessage(InputStream body, HttpHeaders headers, Class<?> deserializationView) {
|
||||
public MappingJacksonInputMessage(@Nullable InputStream body, HttpHeaders headers, Class<?> deserializationView) {
|
||||
this(body, headers);
|
||||
this.deserializationView = deserializationView;
|
||||
}
|
||||
@@ -63,6 +64,7 @@ public class MappingJacksonInputMessage implements HttpInputMessage {
|
||||
this.deserializationView = deserializationView;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Class<?> getDeserializationView() {
|
||||
return this.deserializationView;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -18,6 +18,8 @@ package org.springframework.http.converter.json;
|
||||
|
||||
import com.fasterxml.jackson.databind.ser.FilterProvider;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* A simple holder for the POJO to serialize via
|
||||
* {@link MappingJackson2HttpMessageConverter} along with further
|
||||
@@ -72,7 +74,7 @@ public class MappingJacksonValue {
|
||||
* @see com.fasterxml.jackson.databind.ObjectMapper#writerWithView(Class)
|
||||
* @see com.fasterxml.jackson.annotation.JsonView
|
||||
*/
|
||||
public void setSerializationView(Class<?> serializationView) {
|
||||
public void setSerializationView(@Nullable Class<?> serializationView) {
|
||||
this.serializationView = serializationView;
|
||||
}
|
||||
|
||||
@@ -81,6 +83,7 @@ public class MappingJacksonValue {
|
||||
* @see com.fasterxml.jackson.databind.ObjectMapper#writerWithView(Class)
|
||||
* @see com.fasterxml.jackson.annotation.JsonView
|
||||
*/
|
||||
@Nullable
|
||||
public Class<?> getSerializationView() {
|
||||
return this.serializationView;
|
||||
}
|
||||
@@ -102,6 +105,7 @@ public class MappingJacksonValue {
|
||||
* @see com.fasterxml.jackson.databind.ObjectMapper#writer(FilterProvider)
|
||||
* @see com.fasterxml.jackson.annotation.JsonFilter
|
||||
*/
|
||||
@Nullable
|
||||
public FilterProvider getFilters() {
|
||||
return this.filters;
|
||||
}
|
||||
@@ -116,6 +120,7 @@ public class MappingJacksonValue {
|
||||
/**
|
||||
* Return the configured JSONP function name.
|
||||
*/
|
||||
@Nullable
|
||||
public String getJsonpFunction() {
|
||||
return this.jsonpFunction;
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ import org.springframework.http.converter.AbstractHttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.http.converter.HttpMessageNotWritableException;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import static org.springframework.http.MediaType.*;
|
||||
@@ -105,11 +106,13 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M
|
||||
* initializer that allows the registration of message extensions.
|
||||
* @param registryInitializer an initializer for message extensions
|
||||
*/
|
||||
public ProtobufHttpMessageConverter(ExtensionRegistryInitializer registryInitializer) {
|
||||
public ProtobufHttpMessageConverter(@Nullable ExtensionRegistryInitializer registryInitializer) {
|
||||
this(null, registryInitializer);
|
||||
}
|
||||
|
||||
ProtobufHttpMessageConverter(ProtobufFormatSupport formatSupport, ExtensionRegistryInitializer registryInitializer) {
|
||||
ProtobufHttpMessageConverter(@Nullable ProtobufFormatSupport formatSupport,
|
||||
@Nullable ExtensionRegistryInitializer registryInitializer) {
|
||||
|
||||
if (formatSupport != null) {
|
||||
this.protobufFormatSupport = formatSupport;
|
||||
}
|
||||
@@ -188,6 +191,7 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M
|
||||
MediaType contentType = outputMessage.getHeaders().getContentType();
|
||||
if (contentType == null) {
|
||||
contentType = getDefaultContentType(message);
|
||||
Assert.state(contentType != null, "No content type");
|
||||
}
|
||||
Charset charset = contentType.getCharset();
|
||||
if (charset == null) {
|
||||
@@ -242,12 +246,13 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M
|
||||
|
||||
MediaType[] supportedMediaTypes();
|
||||
|
||||
boolean supportsWriteOnly(MediaType mediaType);
|
||||
boolean supportsWriteOnly(@Nullable MediaType mediaType);
|
||||
|
||||
void merge(InputStream input, Charset charset, MediaType contentType, ExtensionRegistry extensionRegistry,
|
||||
Message.Builder builder) throws IOException;
|
||||
void merge(InputStream input, Charset charset, MediaType contentType,
|
||||
ExtensionRegistry extensionRegistry, Message.Builder builder) throws IOException;
|
||||
|
||||
void print(Message message, OutputStream output, MediaType contentType, Charset charset) throws IOException;
|
||||
void print(Message message, OutputStream output, MediaType contentType, Charset charset)
|
||||
throws IOException;
|
||||
}
|
||||
|
||||
|
||||
@@ -272,7 +277,7 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsWriteOnly(MediaType mediaType) {
|
||||
public boolean supportsWriteOnly(@Nullable MediaType mediaType) {
|
||||
return TEXT_HTML.isCompatibleWith(mediaType);
|
||||
}
|
||||
|
||||
@@ -328,7 +333,7 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsWriteOnly(MediaType mediaType) {
|
||||
public boolean supportsWriteOnly(@Nullable MediaType mediaType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ package org.springframework.http.converter.protobuf;
|
||||
|
||||
import com.google.protobuf.util.JsonFormat;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Subclass of {@link ProtobufHttpMessageConverter} which enforces the use of Protobuf 3 and
|
||||
* its official library {@code "com.google.protobuf:protobuf-java-util"} for JSON processing.
|
||||
@@ -51,7 +53,9 @@ public class ProtobufJsonFormatHttpMessageConverter extends ProtobufHttpMessageC
|
||||
* @param parser the JSON parser configuration
|
||||
* @param printer the JSON printer configuration
|
||||
*/
|
||||
public ProtobufJsonFormatHttpMessageConverter(JsonFormat.Parser parser, JsonFormat.Printer printer) {
|
||||
public ProtobufJsonFormatHttpMessageConverter(
|
||||
@Nullable JsonFormat.Parser parser, @Nullable JsonFormat.Printer printer) {
|
||||
|
||||
this(parser, printer, null);
|
||||
}
|
||||
|
||||
@@ -63,8 +67,8 @@ public class ProtobufJsonFormatHttpMessageConverter extends ProtobufHttpMessageC
|
||||
* @param printer the JSON printer configuration
|
||||
* @param registryInitializer an initializer for message extensions
|
||||
*/
|
||||
public ProtobufJsonFormatHttpMessageConverter(JsonFormat.Parser parser, JsonFormat.Printer printer,
|
||||
ExtensionRegistryInitializer registryInitializer) {
|
||||
public ProtobufJsonFormatHttpMessageConverter(@Nullable JsonFormat.Parser parser,
|
||||
@Nullable JsonFormat.Printer printer, @Nullable ExtensionRegistryInitializer registryInitializer) {
|
||||
|
||||
super(new ProtobufJavaUtilSupport(parser, printer), registryInitializer);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -195,7 +195,7 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa
|
||||
}
|
||||
}
|
||||
|
||||
private void setCharset(MediaType contentType, Marshaller marshaller) throws PropertyException {
|
||||
private void setCharset(@Nullable MediaType contentType, Marshaller marshaller) throws PropertyException {
|
||||
if (contentType != null && contentType.getCharset() != null) {
|
||||
marshaller.setProperty(Marshaller.JAXB_ENCODING, contentType.getCharset().name());
|
||||
}
|
||||
|
||||
@@ -90,11 +90,11 @@ public abstract class AbstractServerHttpRequest implements ServerHttpRequest {
|
||||
if (query != null) {
|
||||
Matcher matcher = QUERY_PATTERN.matcher(query);
|
||||
while (matcher.find()) {
|
||||
String name = matcher.group(1);
|
||||
String name = decodeQueryParam(matcher.group(1));
|
||||
String eq = matcher.group(2);
|
||||
String value = matcher.group(3);
|
||||
value = (value != null ? value : (StringUtils.hasLength(eq) ? "" : null));
|
||||
queryParams.add(decodeQueryParam(name), decodeQueryParam(value));
|
||||
value = (value != null ? decodeQueryParam(value) : (StringUtils.hasLength(eq) ? "" : null));
|
||||
queryParams.add(name, value);
|
||||
}
|
||||
}
|
||||
return queryParams;
|
||||
|
||||
@@ -146,9 +146,7 @@ public abstract class AbstractServerHttpResponse implements ServerHttpResponse {
|
||||
|
||||
@Override
|
||||
public void beforeCommit(Supplier<? extends Mono<Void>> action) {
|
||||
if (action != null) {
|
||||
this.commitActions.add(action);
|
||||
}
|
||||
this.commitActions.add(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.util.function.Function;
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.reactivestreams.Subscriber;
|
||||
import org.reactivestreams.Subscription;
|
||||
import reactor.core.Exceptions;
|
||||
import reactor.core.publisher.MonoSource;
|
||||
import reactor.core.publisher.Operators;
|
||||
|
||||
@@ -246,17 +245,11 @@ public class ChannelSendOperator<T> extends MonoSource<T, Void> {
|
||||
|
||||
@Override
|
||||
public final void onError(Throwable t) {
|
||||
if (t == null) {
|
||||
throw Exceptions.argumentIsNullException();
|
||||
}
|
||||
doError(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onNext(I i) {
|
||||
if (i == null) {
|
||||
throw Exceptions.argumentIsNullException();
|
||||
}
|
||||
try {
|
||||
doNext(i);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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,6 +21,7 @@ import java.net.URISyntaxException;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -108,7 +109,7 @@ class DefaultServerHttpRequestBuilder implements ServerHttpRequest.Builder {
|
||||
private final HttpHeaders httpHeaders;
|
||||
|
||||
public MutativeDecorator(ServerHttpRequest delegate, HttpMethod httpMethod,
|
||||
URI uri, String contextPath, HttpHeaders httpHeaders) {
|
||||
@Nullable URI uri, String contextPath, @Nullable HttpHeaders httpHeaders) {
|
||||
|
||||
super(delegate);
|
||||
this.httpMethod = httpMethod;
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
package org.springframework.http.server.reactive;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
@@ -82,9 +84,9 @@ public class ReactorServerHttpResponse extends AbstractServerHttpResponse implem
|
||||
|
||||
@Override
|
||||
protected void applyHeaders() {
|
||||
for (String name : getHeaders().keySet()) {
|
||||
for (String value : getHeaders().get(name)) {
|
||||
this.response.responseHeaders().add(name, value);
|
||||
for (Map.Entry<String, List<String>> entry : getHeaders().entrySet()) {
|
||||
for (String value : entry.getValue()) {
|
||||
this.response.responseHeaders().add(entry.getKey(), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import io.undertow.connector.PooledByteBuffer;
|
||||
import io.undertow.server.HttpServerExchange;
|
||||
import io.undertow.server.handlers.Cookie;
|
||||
import io.undertow.util.HeaderValues;
|
||||
import org.xnio.ChannelListener;
|
||||
import org.xnio.channels.StreamSourceChannel;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
@@ -118,7 +117,6 @@ public class UndertowServerHttpRequest extends AbstractServerHttpRequest {
|
||||
|
||||
private PooledByteBuffer pooledByteBuffer;
|
||||
|
||||
|
||||
public RequestBodyPublisher(HttpServerExchange exchange, DataBufferFactory bufferFactory) {
|
||||
this.channel = exchange.getRequestChannel();
|
||||
this.bufferFactory = bufferFactory;
|
||||
@@ -130,13 +128,15 @@ public class UndertowServerHttpRequest extends AbstractServerHttpRequest {
|
||||
onAllDataRead();
|
||||
next.proceed();
|
||||
});
|
||||
this.channel.getReadSetter().set((ChannelListener<StreamSourceChannel>) c -> onDataAvailable());
|
||||
this.channel.getCloseSetter().set((ChannelListener<StreamSourceChannel>) c -> onAllDataRead());
|
||||
this.channel.getReadSetter().set(c -> onDataAvailable());
|
||||
this.channel.getCloseSetter().set(c -> onAllDataRead());
|
||||
this.channel.resumeReads();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkOnDataAvailable() {
|
||||
// TODO: The onDataAvailable() call below can cause a StackOverflowError
|
||||
// since this method is being called from onDataAvailable() itself.
|
||||
onDataAvailable();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2017 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,6 +30,7 @@ import com.caucho.hessian.io.SerializerFactory;
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.remoting.RemoteAccessException;
|
||||
import org.springframework.remoting.RemoteConnectFailureException;
|
||||
import org.springframework.remoting.RemoteLookupFailureException;
|
||||
@@ -76,7 +77,7 @@ public class HessianClientInterceptor extends UrlBasedRemoteAccessor implements
|
||||
* <p>Allows to use an externally configured factory instance,
|
||||
* in particular a custom HessianProxyFactory subclass.
|
||||
*/
|
||||
public void setProxyFactory(HessianProxyFactory proxyFactory) {
|
||||
public void setProxyFactory(@Nullable HessianProxyFactory proxyFactory) {
|
||||
this.proxyFactory = (proxyFactory != null ? proxyFactory : new HessianProxyFactory());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -36,6 +36,7 @@ import com.caucho.hessian.server.HessianSkeleton;
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.remoting.support.RemoteExporter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CommonsLogWriter;
|
||||
@@ -74,7 +75,7 @@ public class HessianExporter extends RemoteExporter implements InitializingBean
|
||||
* of type {@code com.caucho.hessian.io.SerializerFactory},
|
||||
* with custom bean property values applied.
|
||||
*/
|
||||
public void setSerializerFactory(SerializerFactory serializerFactory) {
|
||||
public void setSerializerFactory(@Nullable SerializerFactory serializerFactory) {
|
||||
this.serializerFactory = (serializerFactory != null ? serializerFactory : new SerializerFactory());
|
||||
}
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ public abstract class AbstractHttpInvokerRequestExecutor implements HttpInvokerR
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(@Nullable ClassLoader classLoader) {
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.beanClassLoader = classLoader;
|
||||
}
|
||||
|
||||
@@ -234,7 +234,7 @@ public abstract class AbstractHttpInvokerRequestExecutor implements HttpInvokerR
|
||||
* @see #createObjectInputStream
|
||||
* @see #doReadRemoteInvocationResult
|
||||
*/
|
||||
protected RemoteInvocationResult readRemoteInvocationResult(InputStream is, String codebaseUrl)
|
||||
protected RemoteInvocationResult readRemoteInvocationResult(InputStream is, @Nullable String codebaseUrl)
|
||||
throws IOException, ClassNotFoundException {
|
||||
|
||||
ObjectInputStream ois = createObjectInputStream(decorateInputStream(is), codebaseUrl);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -94,7 +94,7 @@ public class HttpComponentsHttpInvokerRequestExecutor extends AbstractHttpInvoke
|
||||
this(httpClient, null);
|
||||
}
|
||||
|
||||
private HttpComponentsHttpInvokerRequestExecutor(HttpClient httpClient, RequestConfig requestConfig) {
|
||||
private HttpComponentsHttpInvokerRequestExecutor(HttpClient httpClient, @Nullable RequestConfig requestConfig) {
|
||||
this.httpClient = httpClient;
|
||||
this.requestConfig = requestConfig;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -42,6 +42,7 @@ import org.springframework.remoting.RemoteAccessException;
|
||||
import org.springframework.remoting.RemoteConnectFailureException;
|
||||
import org.springframework.remoting.RemoteLookupFailureException;
|
||||
import org.springframework.remoting.RemoteProxyFailureException;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -129,6 +130,7 @@ public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory
|
||||
/**
|
||||
* Return the name of the port.
|
||||
*/
|
||||
@Nullable
|
||||
public String getPortName() {
|
||||
return this.portName;
|
||||
}
|
||||
@@ -144,6 +146,7 @@ public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory
|
||||
/**
|
||||
* Return the username to specify on the stub.
|
||||
*/
|
||||
@Nullable
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
@@ -159,6 +162,7 @@ public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory
|
||||
/**
|
||||
* Return the password to specify on the stub.
|
||||
*/
|
||||
@Nullable
|
||||
public String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
@@ -174,6 +178,7 @@ public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory
|
||||
/**
|
||||
* Return the endpoint address to specify on the stub.
|
||||
*/
|
||||
@Nullable
|
||||
public String getEndpointAddress() {
|
||||
return this.endpointAddress;
|
||||
}
|
||||
@@ -219,6 +224,7 @@ public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory
|
||||
/**
|
||||
* Return the SOAP action URI to specify on the stub.
|
||||
*/
|
||||
@Nullable
|
||||
public String getSoapActionUri() {
|
||||
return this.soapActionUri;
|
||||
}
|
||||
@@ -272,7 +278,7 @@ public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory
|
||||
* Set the interface of the service that this factory should create a proxy for.
|
||||
*/
|
||||
public void setServiceInterface(Class<?> serviceInterface) {
|
||||
if (serviceInterface != null && !serviceInterface.isInterface()) {
|
||||
if (!serviceInterface.isInterface()) {
|
||||
throw new IllegalArgumentException("'serviceInterface' must be an interface");
|
||||
}
|
||||
this.serviceInterface = serviceInterface;
|
||||
@@ -281,6 +287,7 @@ public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory
|
||||
/**
|
||||
* Return the interface of the service that this factory should create a proxy for.
|
||||
*/
|
||||
@Nullable
|
||||
public Class<?> getServiceInterface() {
|
||||
return this.serviceInterface;
|
||||
}
|
||||
@@ -300,7 +307,7 @@ public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory
|
||||
* building a client proxy in the {@link JaxWsPortProxyFactoryBean} subclass.
|
||||
*/
|
||||
@Override
|
||||
public void setBeanClassLoader(@Nullable ClassLoader classLoader) {
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.beanClassLoader = classLoader;
|
||||
}
|
||||
|
||||
@@ -324,18 +331,19 @@ public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory
|
||||
*/
|
||||
public void prepare() {
|
||||
Class<?> ifc = getServiceInterface();
|
||||
if (ifc == null) {
|
||||
throw new IllegalArgumentException("Property 'serviceInterface' is required");
|
||||
}
|
||||
Assert.notNull(ifc, "Property 'serviceInterface' is required");
|
||||
|
||||
WebService ann = ifc.getAnnotation(WebService.class);
|
||||
if (ann != null) {
|
||||
applyDefaultsFromAnnotation(ann);
|
||||
}
|
||||
|
||||
Service serviceToUse = getJaxWsService();
|
||||
if (serviceToUse == null) {
|
||||
serviceToUse = createJaxWsService();
|
||||
}
|
||||
this.portQName = getQName(getPortName() != null ? getPortName() : getServiceInterface().getName());
|
||||
|
||||
this.portQName = getQName(getPortName() != null ? getPortName() : ifc.getName());
|
||||
Object stub = getPortStub(serviceToUse, (getPortName() != null ? this.portQName : null));
|
||||
preparePortStub(stub);
|
||||
this.portStub = stub;
|
||||
@@ -407,7 +415,7 @@ public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory
|
||||
* @return the corresponding port object as returned from
|
||||
* {@code Service.getPort(...)}
|
||||
*/
|
||||
protected Object getPortStub(Service service, QName portQName) {
|
||||
protected Object getPortStub(Service service, @Nullable QName portQName) {
|
||||
if (this.portFeatures != null) {
|
||||
return (portQName != null ? service.getPort(portQName, getServiceInterface(), this.portFeatures) :
|
||||
service.getPort(getServiceInterface(), this.portFeatures));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -20,6 +20,7 @@ import javax.xml.ws.BindingProvider;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.FactoryBean} for a specific port of a
|
||||
@@ -40,9 +41,12 @@ public class JaxWsPortProxyFactoryBean extends JaxWsPortClientInterceptor implem
|
||||
public void afterPropertiesSet() {
|
||||
super.afterPropertiesSet();
|
||||
|
||||
Class<?> ifc = getServiceInterface();
|
||||
Assert.notNull(ifc, "Property 'serviceInterface' is required");
|
||||
|
||||
// Build a proxy that also exposes the JAX-WS BindingProvider interface.
|
||||
ProxyFactory pf = new ProxyFactory();
|
||||
pf.addInterface(getServiceInterface());
|
||||
pf.addInterface(ifc);
|
||||
pf.addInterface(BindingProvider.class);
|
||||
pf.addAdvice(this);
|
||||
this.serviceProxy = pf.getProxy(getBeanClassLoader());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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,6 +25,7 @@ import javax.xml.ws.WebServiceFeature;
|
||||
import javax.xml.ws.handler.HandlerResolver;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -77,6 +78,7 @@ public class LocalJaxWsServiceFactory {
|
||||
/**
|
||||
* Return the URL of the WSDL document that describes the service.
|
||||
*/
|
||||
@Nullable
|
||||
public URL getWsdlDocumentUrl() {
|
||||
return this.wsdlDocumentUrl;
|
||||
}
|
||||
@@ -85,13 +87,14 @@ public class LocalJaxWsServiceFactory {
|
||||
* Set the namespace URI of the service.
|
||||
* Corresponds to the WSDL "targetNamespace".
|
||||
*/
|
||||
public void setNamespaceUri(String namespaceUri) {
|
||||
public void setNamespaceUri(@Nullable String namespaceUri) {
|
||||
this.namespaceUri = (namespaceUri != null ? namespaceUri.trim() : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the namespace URI of the service.
|
||||
*/
|
||||
@Nullable
|
||||
public String getNamespaceUri() {
|
||||
return this.namespaceUri;
|
||||
}
|
||||
@@ -107,6 +110,7 @@ public class LocalJaxWsServiceFactory {
|
||||
/**
|
||||
* Return the name of the service.
|
||||
*/
|
||||
@Nullable
|
||||
public String getServiceName() {
|
||||
return this.serviceName;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -19,6 +19,7 @@ package org.springframework.web;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Exception thrown when a client POSTs, PUTs, or PATCHes content of a type
|
||||
@@ -47,8 +48,8 @@ public class HttpMediaTypeNotSupportedException extends HttpMediaTypeException {
|
||||
* @param contentType the unsupported content type
|
||||
* @param supportedMediaTypes the list of supported media types
|
||||
*/
|
||||
public HttpMediaTypeNotSupportedException(MediaType contentType, List<MediaType> supportedMediaTypes) {
|
||||
this(contentType, supportedMediaTypes, "Content type '" + contentType + "' not supported");
|
||||
public HttpMediaTypeNotSupportedException(@Nullable MediaType contentType, List<MediaType> supportedMediaTypes) {
|
||||
this(contentType, supportedMediaTypes, "Content type '" + (contentType != null ? contentType : "") + "' not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,7 +58,7 @@ public class HttpMediaTypeNotSupportedException extends HttpMediaTypeException {
|
||||
* @param supportedMediaTypes the list of supported media types
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public HttpMediaTypeNotSupportedException(MediaType contentType, List<MediaType> supportedMediaTypes, String msg) {
|
||||
public HttpMediaTypeNotSupportedException(@Nullable MediaType contentType, List<MediaType> supportedMediaTypes, String msg) {
|
||||
super(msg, supportedMediaTypes);
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import java.util.EnumSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
@@ -66,7 +65,7 @@ public class HttpRequestMethodNotSupportedException extends ServletException {
|
||||
* @param supportedMethods the actually supported HTTP methods (may be {@code null})
|
||||
*/
|
||||
public HttpRequestMethodNotSupportedException(String method, @Nullable Collection<String> supportedMethods) {
|
||||
this(method, StringUtils.toStringArray(supportedMethods));
|
||||
this(method, (supportedMethods != null ? StringUtils.toStringArray(supportedMethods) : null));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,7 +83,7 @@ public class HttpRequestMethodNotSupportedException extends ServletException {
|
||||
* @param supportedMethods the actually supported HTTP methods
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public HttpRequestMethodNotSupportedException(String method, String[] supportedMethods, String msg) {
|
||||
public HttpRequestMethodNotSupportedException(String method, @Nullable String[] supportedMethods, String msg) {
|
||||
super(msg);
|
||||
this.method = method;
|
||||
this.supportedMethods = supportedMethods;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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,6 +27,7 @@ import javax.servlet.ServletException;
|
||||
import javax.servlet.annotation.HandlesTypes;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
@@ -138,7 +139,7 @@ public class SpringServletContainerInitializer implements ServletContainerInitia
|
||||
* @see AnnotationAwareOrderComparator
|
||||
*/
|
||||
@Override
|
||||
public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
|
||||
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
|
||||
throws ServletException {
|
||||
|
||||
List<WebApplicationInitializer> initializers = new LinkedList<>();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -50,7 +50,7 @@ public abstract class AbstractMappingContentNegotiationStrategy extends MappingM
|
||||
/**
|
||||
* Create an instance with the given map of file extensions and media types.
|
||||
*/
|
||||
public AbstractMappingContentNegotiationStrategy(Map<String, MediaType> mediaTypes) {
|
||||
public AbstractMappingContentNegotiationStrategy(@Nullable Map<String, MediaType> mediaTypes) {
|
||||
super(mediaTypes);
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ public abstract class AbstractMappingContentNegotiationStrategy extends MappingM
|
||||
* an already extracted key.
|
||||
* @since 3.2.16
|
||||
*/
|
||||
public List<MediaType> resolveMediaTypeKey(@Nullable NativeWebRequest webRequest, String key)
|
||||
public List<MediaType> resolveMediaTypeKey(NativeWebRequest webRequest, @Nullable String key)
|
||||
throws HttpMediaTypeNotAcceptableException {
|
||||
|
||||
if (StringUtils.hasText(key)) {
|
||||
@@ -88,7 +88,7 @@ public abstract class AbstractMappingContentNegotiationStrategy extends MappingM
|
||||
|
||||
/**
|
||||
* Extract a key from the request to use to look up media types.
|
||||
* @return the lookup key or {@code null}.
|
||||
* @return the lookup key, or {@code null} if none
|
||||
*/
|
||||
@Nullable
|
||||
protected abstract String getMediaTypeKey(NativeWebRequest request);
|
||||
@@ -113,4 +113,4 @@ public abstract class AbstractMappingContentNegotiationStrategy extends MappingM
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.MediaTypeFactory;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.context.ServletContextAware;
|
||||
@@ -160,7 +161,7 @@ public class ContentNegotiationManagerFactoryBean
|
||||
* @see #setMediaTypes
|
||||
* @see #addMediaType
|
||||
*/
|
||||
public void addMediaTypes(Map<String, MediaType> mediaTypes) {
|
||||
public void addMediaTypes(@Nullable Map<String, MediaType> mediaTypes) {
|
||||
if (mediaTypes != null) {
|
||||
this.mediaTypes.putAll(mediaTypes);
|
||||
}
|
||||
@@ -267,6 +268,11 @@ public class ContentNegotiationManagerFactoryBean
|
||||
}
|
||||
|
||||
|
||||
public ContentNegotiationManager build() {
|
||||
afterPropertiesSet();
|
||||
return this.contentNegotiationManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
List<ContentNegotiationStrategy> strategies = new ArrayList<>();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -55,7 +55,7 @@ public class MappingMediaTypeFileExtensionResolver implements MediaTypeFileExten
|
||||
/**
|
||||
* Create an instance with the given map of file extensions and media types.
|
||||
*/
|
||||
public MappingMediaTypeFileExtensionResolver(Map<String, MediaType> mediaTypes) {
|
||||
public MappingMediaTypeFileExtensionResolver(@Nullable Map<String, MediaType> mediaTypes) {
|
||||
if (mediaTypes != null) {
|
||||
for (Entry<String, MediaType> entries : mediaTypes.entrySet()) {
|
||||
String extension = entries.getKey().toLowerCase(Locale.ENGLISH);
|
||||
|
||||
@@ -69,7 +69,7 @@ public class PathExtensionContentNegotiationStrategy extends AbstractMappingCont
|
||||
/**
|
||||
* Create an instance with the given map of file extensions and media types.
|
||||
*/
|
||||
public PathExtensionContentNegotiationStrategy(Map<String, MediaType> mediaTypes) {
|
||||
public PathExtensionContentNegotiationStrategy(@Nullable Map<String, MediaType> mediaTypes) {
|
||||
super(mediaTypes);
|
||||
this.urlPathHelper.setUrlDecode(false);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import javax.servlet.ServletContext;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
||||
@@ -39,17 +40,6 @@ public class ServletPathExtensionContentNegotiationStrategy extends PathExtensio
|
||||
private final ServletContext servletContext;
|
||||
|
||||
|
||||
/**
|
||||
* Create an instance with the given extension-to-MediaType lookup.
|
||||
*/
|
||||
public ServletPathExtensionContentNegotiationStrategy(
|
||||
ServletContext servletContext, Map<String, MediaType> mediaTypes) {
|
||||
|
||||
super(mediaTypes);
|
||||
Assert.notNull(servletContext, "ServletContext is required");
|
||||
this.servletContext = servletContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance without any mappings to start with. Mappings may be
|
||||
* added later when extensions are resolved through
|
||||
@@ -60,6 +50,17 @@ public class ServletPathExtensionContentNegotiationStrategy extends PathExtensio
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance with the given extension-to-MediaType lookup.
|
||||
*/
|
||||
public ServletPathExtensionContentNegotiationStrategy(
|
||||
ServletContext servletContext, @Nullable Map<String, MediaType> mediaTypes) {
|
||||
|
||||
super(mediaTypes);
|
||||
Assert.notNull(servletContext, "ServletContext is required");
|
||||
this.servletContext = servletContext;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resolve file extension via {@link ServletContext#getMimeType(String)}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -20,6 +20,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.FieldError;
|
||||
import org.springframework.validation.ObjectError;
|
||||
@@ -48,9 +49,7 @@ public class EscapedErrors implements Errors {
|
||||
* Create a new EscapedErrors instance for the given source instance.
|
||||
*/
|
||||
public EscapedErrors(Errors source) {
|
||||
if (source == null) {
|
||||
throw new IllegalArgumentException("Cannot wrap a null instance");
|
||||
}
|
||||
Assert.notNull(source, "Errors source must not be null");
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
@@ -65,7 +64,7 @@ public class EscapedErrors implements Errors {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNestedPath(@Nullable String nestedPath) {
|
||||
public void setNestedPath(String nestedPath) {
|
||||
this.source.setNestedPath(nestedPath);
|
||||
}
|
||||
|
||||
@@ -203,15 +202,20 @@ public class EscapedErrors implements Errors {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getFieldType(@Nullable String field) {
|
||||
public Class<?> getFieldType(String field) {
|
||||
return this.source.getFieldType(field);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T extends ObjectError> T escapeObjectError(T source) {
|
||||
@Nullable
|
||||
private <T extends ObjectError> T escapeObjectError(@Nullable T source) {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
String defaultMessage = source.getDefaultMessage();
|
||||
if (defaultMessage != null) {
|
||||
defaultMessage = HtmlUtils.htmlEscape(defaultMessage);
|
||||
}
|
||||
if (source instanceof FieldError) {
|
||||
FieldError fieldError = (FieldError) source;
|
||||
Object value = fieldError.getRejectedValue();
|
||||
@@ -219,14 +223,12 @@ public class EscapedErrors implements Errors {
|
||||
value = HtmlUtils.htmlEscape((String) value);
|
||||
}
|
||||
return (T) new FieldError(
|
||||
fieldError.getObjectName(), fieldError.getField(), value,
|
||||
fieldError.isBindingFailure(), fieldError.getCodes(),
|
||||
fieldError.getArguments(), HtmlUtils.htmlEscape(fieldError.getDefaultMessage()));
|
||||
fieldError.getObjectName(), fieldError.getField(), value, fieldError.isBindingFailure(),
|
||||
fieldError.getCodes(), fieldError.getArguments(), defaultMessage);
|
||||
}
|
||||
else {
|
||||
return (T) new ObjectError(
|
||||
source.getObjectName(), source.getCodes(), source.getArguments(),
|
||||
HtmlUtils.htmlEscape(source.getDefaultMessage()));
|
||||
source.getObjectName(), source.getCodes(), source.getArguments(), defaultMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -63,7 +63,7 @@ public class MethodArgumentNotValidException extends Exception {
|
||||
public String getMessage() {
|
||||
StringBuilder sb = new StringBuilder("Validation failed for argument at index ")
|
||||
.append(this.parameter.getParameterIndex()).append(" in method: ")
|
||||
.append(this.parameter.getMethod().toGenericString())
|
||||
.append(this.parameter.getExecutable().toGenericString())
|
||||
.append(", with ").append(this.bindingResult.getErrorCount()).append(" error(s): ");
|
||||
for (ObjectError error : this.bindingResult.getAllErrors()) {
|
||||
sb.append("[").append(error).append("] ");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -75,7 +75,7 @@ public class ServletRequestDataBinder extends WebDataBinder {
|
||||
* if the binder is just used to convert a plain parameter value)
|
||||
* @param objectName the name of the target object
|
||||
*/
|
||||
public ServletRequestDataBinder(@Nullable Object target, String objectName) {
|
||||
public ServletRequestDataBinder(@Nullable Object target, @Nullable String objectName) {
|
||||
super(target, objectName);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -19,6 +19,7 @@ package org.springframework.web.bind;
|
||||
import javax.servlet.ServletRequest;
|
||||
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.web.util.WebUtils;
|
||||
|
||||
/**
|
||||
@@ -60,7 +61,7 @@ public class ServletRequestParameterPropertyValues extends MutablePropertyValues
|
||||
* consist of this plus the separator)
|
||||
* @see #DEFAULT_PREFIX_SEPARATOR
|
||||
*/
|
||||
public ServletRequestParameterPropertyValues(ServletRequest request, String prefix) {
|
||||
public ServletRequestParameterPropertyValues(ServletRequest request, @Nullable String prefix) {
|
||||
this(request, prefix, DEFAULT_PREFIX_SEPARATOR);
|
||||
}
|
||||
|
||||
@@ -73,7 +74,9 @@ public class ServletRequestParameterPropertyValues extends MutablePropertyValues
|
||||
* @param prefixSeparator separator delimiting prefix (e.g. "spring")
|
||||
* and the rest of the parameter name ("param1", "param2")
|
||||
*/
|
||||
public ServletRequestParameterPropertyValues(ServletRequest request, String prefix, String prefixSeparator) {
|
||||
public ServletRequestParameterPropertyValues(
|
||||
ServletRequest request, @Nullable String prefix, @Nullable String prefixSeparator) {
|
||||
|
||||
super(WebUtils.getParametersStartingWith(
|
||||
request, (prefix != null ? prefix + prefixSeparator : null)));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -538,7 +538,7 @@ public abstract class ServletRequestUtils {
|
||||
}
|
||||
}
|
||||
|
||||
protected final void validateRequiredParameter(String name, Object parameter)
|
||||
protected final void validateRequiredParameter(String name, @Nullable Object parameter)
|
||||
throws ServletRequestBindingException {
|
||||
|
||||
if (parameter == null) {
|
||||
|
||||
@@ -98,7 +98,7 @@ public class WebDataBinder extends DataBinder {
|
||||
* if the binder is just used to convert a plain parameter value)
|
||||
* @param objectName the name of the target object
|
||||
*/
|
||||
public WebDataBinder(@Nullable Object target, String objectName) {
|
||||
public WebDataBinder(@Nullable Object target, @Nullable String objectName) {
|
||||
super(target, objectName);
|
||||
}
|
||||
|
||||
@@ -131,6 +131,7 @@ public class WebDataBinder extends DataBinder {
|
||||
/**
|
||||
* Return the prefix for parameters that mark potentially empty fields.
|
||||
*/
|
||||
@Nullable
|
||||
public String getFieldMarkerPrefix() {
|
||||
return this.fieldMarkerPrefix;
|
||||
}
|
||||
@@ -156,6 +157,7 @@ public class WebDataBinder extends DataBinder {
|
||||
/**
|
||||
* Return the prefix for parameters that mark default fields.
|
||||
*/
|
||||
@Nullable
|
||||
public String getFieldDefaultPrefix() {
|
||||
return this.fieldDefaultPrefix;
|
||||
}
|
||||
|
||||
@@ -68,8 +68,8 @@ public class DefaultDataBinderFactory implements WebDataBinderFactory {
|
||||
* @param webRequest the current request
|
||||
* @throws Exception in case of invalid state or arguments
|
||||
*/
|
||||
protected WebDataBinder createBinderInstance(@Nullable Object target, String objectName,
|
||||
NativeWebRequest webRequest) throws Exception {
|
||||
protected WebDataBinder createBinderInstance(
|
||||
@Nullable Object target, @Nullable String objectName, NativeWebRequest webRequest) throws Exception {
|
||||
|
||||
return new WebRequestDataBinder(target, objectName);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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,6 +16,7 @@
|
||||
|
||||
package org.springframework.web.bind.support;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
|
||||
@@ -41,7 +42,7 @@ public class DefaultSessionAttributeStore implements SessionAttributeStore {
|
||||
* <p>Default is to use no prefix, storing the session attributes with the
|
||||
* same name as in the model.
|
||||
*/
|
||||
public void setAttributeNamePrefix(String attributeNamePrefix) {
|
||||
public void setAttributeNamePrefix(@Nullable String attributeNamePrefix) {
|
||||
this.attributeNamePrefix = (attributeNamePrefix != null ? attributeNamePrefix : "");
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ public interface SessionAttributeStore {
|
||||
* @param attributeName the name of the attribute
|
||||
* @param attributeValue the attribute value to store
|
||||
*/
|
||||
void storeAttribute(WebRequest request, String attributeName, Object attributeValue);
|
||||
void storeAttribute(WebRequest request, String attributeName, @Nullable Object attributeValue);
|
||||
|
||||
/**
|
||||
* Retrieve the specified attribute from the backend session.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.web.bind.support;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
|
||||
/**
|
||||
@@ -58,6 +59,7 @@ public interface WebArgumentResolver {
|
||||
* @return the argument value, or {@code UNRESOLVED} if not resolvable
|
||||
* @throws Exception in case of resolution failure
|
||||
*/
|
||||
@Nullable
|
||||
Object resolveArgument(MethodParameter methodParameter, NativeWebRequest webRequest) throws Exception;
|
||||
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.util.Map;
|
||||
import org.springframework.beans.PropertyEditorRegistry;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.validation.BeanPropertyBindingResult;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.Errors;
|
||||
@@ -67,7 +68,7 @@ public class WebExchangeBindException extends ServerWebInputException implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNestedPath(@Nullable String nestedPath) {
|
||||
public void setNestedPath(String nestedPath) {
|
||||
this.bindingResult.setNestedPath(nestedPath);
|
||||
}
|
||||
|
||||
@@ -113,7 +114,9 @@ public class WebExchangeBindException extends ServerWebInputException implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rejectValue(@Nullable String field, String errorCode, @Nullable Object[] errorArgs, @Nullable String defaultMessage) {
|
||||
public void rejectValue(
|
||||
@Nullable String field, String errorCode, @Nullable Object[] errorArgs, @Nullable String defaultMessage) {
|
||||
|
||||
this.bindingResult.rejectValue(field, errorCode, errorArgs, defaultMessage);
|
||||
}
|
||||
|
||||
@@ -204,7 +207,7 @@ public class WebExchangeBindException extends ServerWebInputException implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getFieldType(@Nullable String field) {
|
||||
public Class<?> getFieldType(String field) {
|
||||
return this.bindingResult.getFieldType(field);
|
||||
}
|
||||
|
||||
@@ -266,9 +269,10 @@ public class WebExchangeBindException extends ServerWebInputException implements
|
||||
@Override
|
||||
public String getMessage() {
|
||||
MethodParameter parameter = getMethodParameter();
|
||||
Assert.state(parameter != null, "No MethodParameter");
|
||||
StringBuilder sb = new StringBuilder("Validation failed for argument at index ")
|
||||
.append(parameter.getParameterIndex()).append(" in method: ")
|
||||
.append(parameter.getMethod().toGenericString())
|
||||
.append(parameter.getExecutable().toGenericString())
|
||||
.append(", with ").append(this.bindingResult.getErrorCount()).append(" error(s): ");
|
||||
for (ObjectError error : this.bindingResult.getAllErrors()) {
|
||||
sb.append("[").append(error).append("] ");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -18,7 +18,6 @@ package org.springframework.web.bind.support;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.Part;
|
||||
|
||||
@@ -87,7 +86,7 @@ public class WebRequestDataBinder extends WebDataBinder {
|
||||
* if the binder is just used to convert a plain parameter value)
|
||||
* @param objectName the name of the target object
|
||||
*/
|
||||
public WebRequestDataBinder(@Nullable Object target, String objectName) {
|
||||
public WebRequestDataBinder(@Nullable Object target, @Nullable String objectName) {
|
||||
super(target, objectName);
|
||||
}
|
||||
|
||||
@@ -119,7 +118,9 @@ public class WebRequestDataBinder extends WebDataBinder {
|
||||
}
|
||||
else {
|
||||
HttpServletRequest servletRequest = ((NativeWebRequest) request).getNativeRequest(HttpServletRequest.class);
|
||||
bindParts(servletRequest, mpvs);
|
||||
if (servletRequest != null) {
|
||||
bindParts(servletRequest, mpvs);
|
||||
}
|
||||
}
|
||||
}
|
||||
doBind(mpvs);
|
||||
|
||||
@@ -556,7 +556,7 @@ public class AsyncRestTemplate extends org.springframework.http.client.support.I
|
||||
* Returns a request callback implementation that writes the given object to the
|
||||
* request stream.
|
||||
*/
|
||||
protected <T> AsyncRequestCallback httpEntityCallback(HttpEntity<T> requestBody) {
|
||||
protected <T> AsyncRequestCallback httpEntityCallback(@Nullable HttpEntity<T> requestBody) {
|
||||
return new AsyncRequestCallbackAdapter(this.syncTemplate.httpEntityCallback(requestBody));
|
||||
}
|
||||
|
||||
@@ -564,7 +564,7 @@ public class AsyncRestTemplate extends org.springframework.http.client.support.I
|
||||
* Returns a request callback implementation that writes the given object to the
|
||||
* request stream.
|
||||
*/
|
||||
protected <T> AsyncRequestCallback httpEntityCallback(HttpEntity<T> request, Type responseType) {
|
||||
protected <T> AsyncRequestCallback httpEntityCallback(@Nullable HttpEntity<T> request, Type responseType) {
|
||||
return new AsyncRequestCallbackAdapter(this.syncTemplate.httpEntityCallback(request, responseType));
|
||||
}
|
||||
|
||||
@@ -596,7 +596,9 @@ public class AsyncRestTemplate extends org.springframework.http.client.support.I
|
||||
private final ResponseExtractor<T> responseExtractor;
|
||||
|
||||
public ResponseExtractorFuture(HttpMethod method, URI url,
|
||||
ListenableFuture<ClientHttpResponse> clientHttpResponseFuture, ResponseExtractor<T> responseExtractor) {
|
||||
ListenableFuture<ClientHttpResponse> clientHttpResponseFuture,
|
||||
@Nullable ResponseExtractor<T> responseExtractor) {
|
||||
|
||||
super(clientHttpResponseFuture);
|
||||
this.method = method;
|
||||
this.url = url;
|
||||
@@ -618,12 +620,11 @@ public class AsyncRestTemplate extends org.springframework.http.client.support.I
|
||||
throw new ExecutionException(ex);
|
||||
}
|
||||
finally {
|
||||
if (response != null) {
|
||||
response.close();
|
||||
}
|
||||
response.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected T convertResponse(ClientHttpResponse response) throws IOException {
|
||||
return (this.responseExtractor != null ? this.responseExtractor.extractData(response) : null);
|
||||
}
|
||||
@@ -648,34 +649,32 @@ public class AsyncRestTemplate extends org.springframework.http.client.support.I
|
||||
|
||||
@Override
|
||||
public void doWithRequest(final org.springframework.http.client.AsyncClientHttpRequest request) throws IOException {
|
||||
if (this.adaptee != null) {
|
||||
this.adaptee.doWithRequest(new ClientHttpRequest() {
|
||||
@Override
|
||||
public ClientHttpResponse execute() throws IOException {
|
||||
throw new UnsupportedOperationException("execute not supported");
|
||||
}
|
||||
@Override
|
||||
public OutputStream getBody() throws IOException {
|
||||
return request.getBody();
|
||||
}
|
||||
@Override
|
||||
public HttpMethod getMethod() {
|
||||
return request.getMethod();
|
||||
}
|
||||
@Override
|
||||
public String getMethodValue() {
|
||||
return request.getMethodValue();
|
||||
}
|
||||
@Override
|
||||
public URI getURI() {
|
||||
return request.getURI();
|
||||
}
|
||||
@Override
|
||||
public HttpHeaders getHeaders() {
|
||||
return request.getHeaders();
|
||||
}
|
||||
});
|
||||
}
|
||||
this.adaptee.doWithRequest(new ClientHttpRequest() {
|
||||
@Override
|
||||
public ClientHttpResponse execute() throws IOException {
|
||||
throw new UnsupportedOperationException("execute not supported");
|
||||
}
|
||||
@Override
|
||||
public OutputStream getBody() throws IOException {
|
||||
return request.getBody();
|
||||
}
|
||||
@Override
|
||||
public HttpMethod getMethod() {
|
||||
return request.getMethod();
|
||||
}
|
||||
@Override
|
||||
public String getMethodValue() {
|
||||
return request.getMethodValue();
|
||||
}
|
||||
@Override
|
||||
public URI getURI() {
|
||||
return request.getURI();
|
||||
}
|
||||
@Override
|
||||
public HttpHeaders getHeaders() {
|
||||
return request.getHeaders();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -61,7 +61,7 @@ class MessageBodyClientHttpResponseWrapper implements ClientHttpResponse {
|
||||
responseStatus == HttpStatus.NOT_MODIFIED) {
|
||||
return false;
|
||||
}
|
||||
else if (this.getHeaders().getContentLength() == 0) {
|
||||
else if (getHeaders().getContentLength() == 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -79,10 +79,7 @@ class MessageBodyClientHttpResponseWrapper implements ClientHttpResponse {
|
||||
*/
|
||||
public boolean hasEmptyMessageBody() throws IOException {
|
||||
InputStream body = this.response.getBody();
|
||||
if (body == null) {
|
||||
return true;
|
||||
}
|
||||
else if (body.markSupported()) {
|
||||
if (body.markSupported()) {
|
||||
body.mark(1);
|
||||
if (body.read() == -1) {
|
||||
return true;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -154,6 +154,7 @@ public interface RestOperations {
|
||||
* @return the value for the {@code Location} header
|
||||
* @see HttpEntity
|
||||
*/
|
||||
@Nullable
|
||||
URI postForLocation(String url, @Nullable Object request, Object... uriVariables) throws RestClientException;
|
||||
|
||||
/**
|
||||
@@ -168,6 +169,7 @@ public interface RestOperations {
|
||||
* @return the value for the {@code Location} header
|
||||
* @see HttpEntity
|
||||
*/
|
||||
@Nullable
|
||||
URI postForLocation(String url, @Nullable Object request, Map<String, ?> uriVariables) throws RestClientException;
|
||||
|
||||
/**
|
||||
@@ -180,6 +182,7 @@ public interface RestOperations {
|
||||
* @return the value for the {@code Location} header
|
||||
* @see HttpEntity
|
||||
*/
|
||||
@Nullable
|
||||
URI postForLocation(URI url, @Nullable Object request) throws RestClientException;
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -339,7 +340,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
|
||||
|
||||
RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
|
||||
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
|
||||
return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables);
|
||||
return nonNull(execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -348,14 +349,14 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
|
||||
|
||||
RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
|
||||
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
|
||||
return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables);
|
||||
return nonNull(execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType) throws RestClientException {
|
||||
RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
|
||||
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
|
||||
return execute(url, HttpMethod.GET, requestCallback, responseExtractor);
|
||||
return nonNull(execute(url, HttpMethod.GET, requestCallback, responseExtractor));
|
||||
}
|
||||
|
||||
|
||||
@@ -363,17 +364,17 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
|
||||
|
||||
@Override
|
||||
public HttpHeaders headForHeaders(String url, Object... uriVariables) throws RestClientException {
|
||||
return execute(url, HttpMethod.HEAD, null, headersExtractor(), uriVariables);
|
||||
return nonNull(execute(url, HttpMethod.HEAD, null, headersExtractor(), uriVariables));
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders headForHeaders(String url, Map<String, ?> uriVariables) throws RestClientException {
|
||||
return execute(url, HttpMethod.HEAD, null, headersExtractor(), uriVariables);
|
||||
return nonNull(execute(url, HttpMethod.HEAD, null, headersExtractor(), uriVariables));
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders headForHeaders(URI url) throws RestClientException {
|
||||
return execute(url, HttpMethod.HEAD, null, headersExtractor());
|
||||
return nonNull(execute(url, HttpMethod.HEAD, null, headersExtractor()));
|
||||
}
|
||||
|
||||
|
||||
@@ -383,21 +384,21 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
|
||||
public URI postForLocation(String url, @Nullable Object request, Object... uriVariables) throws RestClientException {
|
||||
RequestCallback requestCallback = httpEntityCallback(request);
|
||||
HttpHeaders headers = execute(url, HttpMethod.POST, requestCallback, headersExtractor(), uriVariables);
|
||||
return headers.getLocation();
|
||||
return (headers != null ? headers.getLocation() : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI postForLocation(String url, @Nullable Object request, Map<String, ?> uriVariables) throws RestClientException {
|
||||
RequestCallback requestCallback = httpEntityCallback(request);
|
||||
HttpHeaders headers = execute(url, HttpMethod.POST, requestCallback, headersExtractor(), uriVariables);
|
||||
return headers.getLocation();
|
||||
return (headers != null ? headers.getLocation() : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI postForLocation(URI url, @Nullable Object request) throws RestClientException {
|
||||
RequestCallback requestCallback = httpEntityCallback(request);
|
||||
HttpHeaders headers = execute(url, HttpMethod.POST, requestCallback, headersExtractor());
|
||||
return headers.getLocation();
|
||||
return (headers != null ? headers.getLocation() : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -434,7 +435,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
|
||||
|
||||
RequestCallback requestCallback = httpEntityCallback(request, responseType);
|
||||
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
|
||||
return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);
|
||||
return nonNull(execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -443,14 +444,14 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
|
||||
|
||||
RequestCallback requestCallback = httpEntityCallback(request, responseType);
|
||||
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
|
||||
return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);
|
||||
return nonNull(execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ResponseEntity<T> postForEntity(URI url, @Nullable Object request, Class<T> responseType) throws RestClientException {
|
||||
RequestCallback requestCallback = httpEntityCallback(request, responseType);
|
||||
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
|
||||
return execute(url, HttpMethod.POST, requestCallback, responseExtractor);
|
||||
return nonNull(execute(url, HttpMethod.POST, requestCallback, responseExtractor));
|
||||
}
|
||||
|
||||
|
||||
@@ -532,21 +533,21 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
|
||||
public Set<HttpMethod> optionsForAllow(String url, Object... uriVariables) throws RestClientException {
|
||||
ResponseExtractor<HttpHeaders> headersExtractor = headersExtractor();
|
||||
HttpHeaders headers = execute(url, HttpMethod.OPTIONS, null, headersExtractor, uriVariables);
|
||||
return headers.getAllow();
|
||||
return (headers != null ? headers.getAllow() : Collections.emptySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<HttpMethod> optionsForAllow(String url, Map<String, ?> uriVariables) throws RestClientException {
|
||||
ResponseExtractor<HttpHeaders> headersExtractor = headersExtractor();
|
||||
HttpHeaders headers = execute(url, HttpMethod.OPTIONS, null, headersExtractor, uriVariables);
|
||||
return headers.getAllow();
|
||||
return (headers != null ? headers.getAllow() : Collections.emptySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<HttpMethod> optionsForAllow(URI url) throws RestClientException {
|
||||
ResponseExtractor<HttpHeaders> headersExtractor = headersExtractor();
|
||||
HttpHeaders headers = execute(url, HttpMethod.OPTIONS, null, headersExtractor);
|
||||
return headers.getAllow();
|
||||
return (headers != null ? headers.getAllow() : Collections.emptySet());
|
||||
}
|
||||
|
||||
|
||||
@@ -558,7 +559,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
|
||||
|
||||
RequestCallback requestCallback = httpEntityCallback(requestEntity, responseType);
|
||||
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
|
||||
return execute(url, method, requestCallback, responseExtractor, uriVariables);
|
||||
return nonNull(execute(url, method, requestCallback, responseExtractor, uriVariables));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -567,7 +568,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
|
||||
|
||||
RequestCallback requestCallback = httpEntityCallback(requestEntity, responseType);
|
||||
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
|
||||
return execute(url, method, requestCallback, responseExtractor, uriVariables);
|
||||
return nonNull(execute(url, method, requestCallback, responseExtractor, uriVariables));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -576,7 +577,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
|
||||
|
||||
RequestCallback requestCallback = httpEntityCallback(requestEntity, responseType);
|
||||
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
|
||||
return execute(url, method, requestCallback, responseExtractor);
|
||||
return nonNull(execute(url, method, requestCallback, responseExtractor));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -586,7 +587,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
|
||||
Type type = responseType.getType();
|
||||
RequestCallback requestCallback = httpEntityCallback(requestEntity, type);
|
||||
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(type);
|
||||
return execute(url, method, requestCallback, responseExtractor, uriVariables);
|
||||
return nonNull(execute(url, method, requestCallback, responseExtractor, uriVariables));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -596,7 +597,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
|
||||
Type type = responseType.getType();
|
||||
RequestCallback requestCallback = httpEntityCallback(requestEntity, type);
|
||||
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(type);
|
||||
return execute(url, method, requestCallback, responseExtractor, uriVariables);
|
||||
return nonNull(execute(url, method, requestCallback, responseExtractor, uriVariables));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -606,30 +607,30 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
|
||||
Type type = responseType.getType();
|
||||
RequestCallback requestCallback = httpEntityCallback(requestEntity, type);
|
||||
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(type);
|
||||
return execute(url, method, requestCallback, responseExtractor);
|
||||
return nonNull(execute(url, method, requestCallback, responseExtractor));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ResponseEntity<T> exchange(RequestEntity<?> requestEntity, Class<T> responseType)
|
||||
throws RestClientException {
|
||||
|
||||
Assert.notNull(requestEntity, "'requestEntity' must not be null");
|
||||
Assert.notNull(requestEntity, "RequestEntity must not be null");
|
||||
|
||||
RequestCallback requestCallback = httpEntityCallback(requestEntity, responseType);
|
||||
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
|
||||
return execute(requestEntity.getUrl(), requestEntity.getMethod(), requestCallback, responseExtractor);
|
||||
return nonNull(execute(requestEntity.getUrl(), requestEntity.getMethod(), requestCallback, responseExtractor));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ResponseEntity<T> exchange(RequestEntity<?> requestEntity, ParameterizedTypeReference<T> responseType)
|
||||
throws RestClientException {
|
||||
|
||||
Assert.notNull(requestEntity, "'requestEntity' must not be null");
|
||||
Assert.notNull(requestEntity, "RequestEntity must not be null");
|
||||
|
||||
Type type = responseType.getType();
|
||||
RequestCallback requestCallback = httpEntityCallback(requestEntity, type);
|
||||
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(type);
|
||||
return execute(requestEntity.getUrl(), requestEntity.getMethod(), requestCallback, responseExtractor);
|
||||
return nonNull(execute(requestEntity.getUrl(), requestEntity.getMethod(), requestCallback, responseExtractor));
|
||||
}
|
||||
|
||||
|
||||
@@ -652,7 +653,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T execute(URI url, HttpMethod method, @Nullable RequestCallback requestCallback,
|
||||
public <T> T execute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback,
|
||||
@Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {
|
||||
|
||||
return doExecute(url, method, requestCallback, responseExtractor);
|
||||
@@ -669,7 +670,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
|
||||
* @return an arbitrary object, as returned by the {@link ResponseExtractor}
|
||||
*/
|
||||
@Nullable
|
||||
protected <T> T doExecute(URI url, HttpMethod method, @Nullable RequestCallback requestCallback,
|
||||
protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback,
|
||||
@Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {
|
||||
|
||||
Assert.notNull(url, "'url' must not be null");
|
||||
@@ -745,7 +746,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
|
||||
* Returns a request callback implementation that writes the given object to the
|
||||
* request stream.
|
||||
*/
|
||||
protected <T> RequestCallback httpEntityCallback(Object requestBody) {
|
||||
protected <T> RequestCallback httpEntityCallback(@Nullable Object requestBody) {
|
||||
return new HttpEntityRequestCallback(requestBody);
|
||||
}
|
||||
|
||||
@@ -753,7 +754,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
|
||||
* Returns a request callback implementation that writes the given object to the
|
||||
* request stream.
|
||||
*/
|
||||
protected <T> RequestCallback httpEntityCallback(Object requestBody, Type responseType) {
|
||||
protected <T> RequestCallback httpEntityCallback(@Nullable Object requestBody, Type responseType) {
|
||||
return new HttpEntityRequestCallback(requestBody, responseType);
|
||||
}
|
||||
|
||||
@@ -771,6 +772,11 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
|
||||
return this.headersExtractor;
|
||||
}
|
||||
|
||||
private static <T> T nonNull(@Nullable T result) {
|
||||
Assert.state(result != null, "No result");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Request callback implementation that prepares the request's accept headers.
|
||||
@@ -779,7 +785,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
|
||||
|
||||
private final Type responseType;
|
||||
|
||||
private AcceptHeaderRequestCallback(Type responseType) {
|
||||
private AcceptHeaderRequestCallback(@Nullable Type responseType) {
|
||||
this.responseType = responseType;
|
||||
}
|
||||
|
||||
@@ -836,11 +842,11 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
|
||||
|
||||
private final HttpEntity<?> requestEntity;
|
||||
|
||||
private HttpEntityRequestCallback(Object requestBody) {
|
||||
private HttpEntityRequestCallback(@Nullable Object requestBody) {
|
||||
this(requestBody, null);
|
||||
}
|
||||
|
||||
private HttpEntityRequestCallback(Object requestBody, Type responseType) {
|
||||
private HttpEntityRequestCallback(@Nullable Object requestBody, @Nullable Type responseType) {
|
||||
super(responseType);
|
||||
if (requestBody instanceof HttpEntity) {
|
||||
this.requestEntity = (HttpEntity<?>) requestBody;
|
||||
@@ -857,7 +863,8 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
|
||||
@SuppressWarnings("unchecked")
|
||||
public void doWithRequest(ClientHttpRequest httpRequest) throws IOException {
|
||||
super.doWithRequest(httpRequest);
|
||||
if (!this.requestEntity.hasBody()) {
|
||||
Object requestBody = this.requestEntity.getBody();
|
||||
if (requestBody == null) {
|
||||
HttpHeaders httpHeaders = httpRequest.getHeaders();
|
||||
HttpHeaders requestHeaders = this.requestEntity.getHeaders();
|
||||
if (!requestHeaders.isEmpty()) {
|
||||
@@ -868,7 +875,6 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
|
||||
}
|
||||
}
|
||||
else {
|
||||
Object requestBody = this.requestEntity.getBody();
|
||||
Class<?> requestBodyClass = requestBody.getClass();
|
||||
Type requestBodyType = (this.requestEntity instanceof RequestEntity ?
|
||||
((RequestEntity<?>)this.requestEntity).getType() : requestBodyClass);
|
||||
@@ -933,7 +939,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
|
||||
|
||||
private final HttpMessageConverterExtractor<T> delegate;
|
||||
|
||||
public ResponseEntityResponseExtractor(Type responseType) {
|
||||
public ResponseEntityResponseExtractor(@Nullable Type responseType) {
|
||||
if (responseType != null && Void.class != responseType) {
|
||||
this.delegate = new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -236,7 +235,7 @@ public class ContextLoader {
|
||||
* @see #customizeContext
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setContextInitializers(ApplicationContextInitializer<?>... initializers) {
|
||||
public void setContextInitializers(@Nullable ApplicationContextInitializer<?>... initializers) {
|
||||
if (initializers != null) {
|
||||
for (ApplicationContextInitializer<?> initializer : initializers) {
|
||||
this.contextInitializers.add((ApplicationContextInitializer<ConfigurableApplicationContext>) initializer);
|
||||
|
||||
@@ -99,7 +99,6 @@ public interface WebApplicationContext extends ApplicationContext {
|
||||
|
||||
/**
|
||||
* Return the standard Servlet API ServletContext for this application.
|
||||
* <p>Also available for a Portlet application, in addition to the PortletContext.
|
||||
*/
|
||||
@Nullable
|
||||
ServletContext getServletContext();
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.web.context.request;
|
||||
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.beans.factory.config.Scope;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Abstract {@link Scope} implementation that reads from a particular scope
|
||||
@@ -42,6 +43,7 @@ public abstract class AbstractRequestAttributesScope implements Scope {
|
||||
Object scopedObject = attributes.getAttribute(name, getScope());
|
||||
if (scopedObject == null) {
|
||||
scopedObject = objectFactory.getObject();
|
||||
Assert.state(scopedObject != null, "Scoped object resolved to null");
|
||||
attributes.setAttribute(name, scopedObject, getScope());
|
||||
// Retrieve object again, registering it for implicit session attribute updates.
|
||||
// As a bonus, we also allow for potential decoration at the getAttribute level.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -193,7 +193,7 @@ public class FacesRequestAttributes implements RequestAttributes {
|
||||
try {
|
||||
// Both HttpSession and PortletSession have a getId() method.
|
||||
Method getIdMethod = session.getClass().getMethod("getId");
|
||||
return ReflectionUtils.invokeMethod(getIdMethod, session).toString();
|
||||
return String.valueOf(ReflectionUtils.invokeMethod(getIdMethod, session));
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
throw new IllegalStateException("Session object [" + session + "] does not have a getId() method");
|
||||
|
||||
@@ -58,7 +58,7 @@ public class FacesWebRequest extends FacesRequestAttributes implements NativeWeb
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getNativeRequest(Class<T> requiredType) {
|
||||
public <T> T getNativeRequest(@Nullable Class<T> requiredType) {
|
||||
if (requiredType != null) {
|
||||
Object request = getExternalContext().getRequest();
|
||||
if (requiredType.isInstance(request)) {
|
||||
@@ -70,7 +70,7 @@ public class FacesWebRequest extends FacesRequestAttributes implements NativeWeb
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getNativeResponse(Class<T> requiredType) {
|
||||
public <T> T getNativeResponse(@Nullable Class<T> requiredType) {
|
||||
if (requiredType != null) {
|
||||
Object response = getExternalContext().getResponse();
|
||||
if (requiredType.isInstance(response)) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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,15 +31,16 @@ import org.springframework.lang.Nullable;
|
||||
public interface NativeWebRequest extends WebRequest {
|
||||
|
||||
/**
|
||||
* Return the underlying native request object, if available.
|
||||
* Return the underlying native request object.
|
||||
* @see javax.servlet.http.HttpServletRequest
|
||||
*/
|
||||
Object getNativeRequest();
|
||||
|
||||
/**
|
||||
* Return the underlying native response object, if available.
|
||||
* Return the underlying native response object, if any.
|
||||
* @see javax.servlet.http.HttpServletResponse
|
||||
*/
|
||||
@Nullable
|
||||
Object getNativeResponse();
|
||||
|
||||
/**
|
||||
@@ -50,7 +51,7 @@ public interface NativeWebRequest extends WebRequest {
|
||||
* @see javax.servlet.http.HttpServletRequest
|
||||
*/
|
||||
@Nullable
|
||||
<T> T getNativeRequest(Class<T> requiredType);
|
||||
<T> T getNativeRequest(@Nullable Class<T> requiredType);
|
||||
|
||||
/**
|
||||
* Return the underlying native response object, if available.
|
||||
@@ -60,6 +61,6 @@ public interface NativeWebRequest extends WebRequest {
|
||||
* @see javax.servlet.http.HttpServletResponse
|
||||
*/
|
||||
@Nullable
|
||||
<T> T getNativeResponse(Class<T> requiredType);
|
||||
<T> T getNativeResponse(@Nullable Class<T> requiredType);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -132,7 +132,6 @@ public interface RequestAttributes {
|
||||
* Return an id for the current underlying session.
|
||||
* @return the session id as String (never {@code null})
|
||||
*/
|
||||
@Nullable
|
||||
String getSessionId();
|
||||
|
||||
/**
|
||||
@@ -140,7 +139,6 @@ public interface RequestAttributes {
|
||||
* that is, an object to synchronize on for the underlying session.
|
||||
* @return the session mutex to use (never {@code null})
|
||||
*/
|
||||
@Nullable
|
||||
Object getSessionMutex();
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user