Consistent support for if-(un)modified-since as ZonedDateTime/Instant

Includes DefaultRequestBodyUriSpec pre-resolving URI for HttpRequest.

Issue: SPR-17571
This commit is contained in:
Juergen Hoeller
2018-12-17 16:21:39 +01:00
parent 199be6aec5
commit a240cfcf2f
8 changed files with 142 additions and 90 deletions

View File

@@ -1079,6 +1079,24 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
return getETagValuesAsList(IF_MATCH);
}
/**
* Set the time the resource was last changed, as specified by the
* {@code Last-Modified} header.
* @since 5.1.4
*/
public void setIfModifiedSince(ZonedDateTime ifModifiedSince) {
setZonedDateTime(IF_MODIFIED_SINCE, ifModifiedSince.withZoneSameInstant(GMT));
}
/**
* Set the time the resource was last changed, as specified by the
* {@code Last-Modified} header.
* @since 5.1.4
*/
public void setIfModifiedSince(Instant ifModifiedSince) {
setInstant(IF_MODIFIED_SINCE, ifModifiedSince);
}
/**
* Set the (new) value of the {@code If-Modified-Since} header.
* <p>The date should be specified as the number of milliseconds since
@@ -1119,6 +1137,24 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
return getETagValuesAsList(IF_NONE_MATCH);
}
/**
* Set the time the resource was last changed, as specified by the
* {@code Last-Modified} header.
* @since 5.1.4
*/
public void setIfUnmodifiedSince(ZonedDateTime ifUnmodifiedSince) {
setZonedDateTime(IF_UNMODIFIED_SINCE, ifUnmodifiedSince.withZoneSameInstant(GMT));
}
/**
* Set the time the resource was last changed, as specified by the
* {@code Last-Modified} header.
* @since 5.1.4
*/
public void setIfUnmodifiedSince(Instant ifUnmodifiedSince) {
setInstant(IF_UNMODIFIED_SINCE, ifUnmodifiedSince);
}
/**
* Set the (new) value of the {@code If-Unmodified-Since} header.
* <p>The date should be specified as the number of milliseconds since
@@ -1143,11 +1179,10 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
/**
* Set the time the resource was last changed, as specified by the
* {@code Last-Modified} header.
* <p>The date should be specified as the number of milliseconds since
* January 1, 1970 GMT.
* @since 5.1.4
*/
public void setLastModified(long lastModified) {
setDate(LAST_MODIFIED, lastModified);
public void setLastModified(ZonedDateTime lastModified) {
setZonedDateTime(LAST_MODIFIED, lastModified.withZoneSameInstant(GMT));
}
/**
@@ -1162,10 +1197,11 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
/**
* Set the time the resource was last changed, as specified by the
* {@code Last-Modified} header.
* @since 5.1.4
* <p>The date should be specified as the number of milliseconds since
* January 1, 1970 GMT.
*/
public void setLastModified(ZonedDateTime lastModified) {
setZonedDateTime(LAST_MODIFIED, lastModified.withZoneSameInstant(GMT));
public void setLastModified(long lastModified) {
setDate(LAST_MODIFIED, lastModified);
}
/**
@@ -1283,20 +1319,20 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
* Set the given date under the given header name after formatting it as a string
* using the RFC-1123 date-time formatter. The equivalent of
* {@link #set(String, String)} but for date headers.
* @since 5.1.4
* @since 5.0
*/
public void setInstant(String headerName, Instant date) {
setZonedDateTime(headerName, ZonedDateTime.ofInstant(date, GMT));
public void setZonedDateTime(String headerName, ZonedDateTime date) {
set(headerName, DATE_FORMATTERS[0].format(date));
}
/**
* Set the given date under the given header name after formatting it as a string
* using the RFC-1123 date-time formatter. The equivalent of
* {@link #set(String, String)} but for date headers.
* @since 5.0
* @since 5.1.4
*/
public void setZonedDateTime(String headerName, ZonedDateTime date) {
set(headerName, DATE_FORMATTERS[0].format(date));
public void setInstant(String headerName, Instant date) {
setZonedDateTime(headerName, ZonedDateTime.ofInstant(date, GMT));
}
/**
@@ -1643,25 +1679,6 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
return formatHeaders(this.headers);
}
/**
* Helps to format HTTP header values, as HTTP header values themselves can
* contain comma-separated values, can become confusing with regular
* {@link Map} formatting that also uses commas between entries.
* @param headers the headers to format
* @return the headers to a String
* @since 5.1.4
*/
public static String formatHeaders(MultiValueMap<String, String> headers) {
return headers.entrySet().stream()
.map(entry -> {
List<String> values = entry.getValue();
return entry.getKey() + ":" + (values.size() == 1 ?
"\"" + values.get(0) + "\"" :
values.stream().map(s -> "\"" + s + "\"").collect(Collectors.joining(", ")));
})
.collect(Collectors.joining(", ", "[", "]"));
}
/**
* Return a {@code HttpHeaders} object that can only be read, not written to.
@@ -1689,6 +1706,25 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
}
}
/**
* Helps to format HTTP header values, as HTTP header values themselves can
* contain comma-separated values, can become confusing with regular
* {@link Map} formatting that also uses commas between entries.
* @param headers the headers to format
* @return the headers to a String
* @since 5.1.4
*/
public static String formatHeaders(MultiValueMap<String, String> headers) {
return headers.entrySet().stream()
.map(entry -> {
List<String> values = entry.getValue();
return entry.getKey() + ":" + (values.size() == 1 ?
"\"" + values.get(0) + "\"" :
values.stream().map(s -> "\"" + s + "\"").collect(Collectors.joining(", ")));
})
.collect(Collectors.joining(", ", "[", "]"));
}
// Package-private: used in ResponseCookie
static String formatDate(long date) {
Instant instant = Instant.ofEpochMilli(date);

View File

@@ -19,6 +19,8 @@ package org.springframework.http;
import java.lang.reflect.Type;
import java.net.URI;
import java.nio.charset.Charset;
import java.time.Instant;
import java.time.ZonedDateTime;
import java.util.Arrays;
import org.springframework.lang.Nullable;
@@ -327,6 +329,20 @@ public class RequestEntity<T> extends HttpEntity<T> {
*/
B acceptCharset(Charset... acceptableCharsets);
/**
* Set the value of the {@code If-Modified-Since} header.
* @param ifModifiedSince the new value of the header
* @since 5.1.4
*/
B ifModifiedSince(ZonedDateTime ifModifiedSince);
/**
* Set the value of the {@code If-Modified-Since} header.
* @param ifModifiedSince the new value of the header
* @since 5.1.4
*/
B ifModifiedSince(Instant ifModifiedSince);
/**
* Set the value of the {@code If-Modified-Since} header.
* <p>The date should be specified as the number of milliseconds since
@@ -438,6 +454,18 @@ public class RequestEntity<T> extends HttpEntity<T> {
return this;
}
@Override
public BodyBuilder ifModifiedSince(ZonedDateTime ifModifiedSince) {
this.headers.setIfModifiedSince(ifModifiedSince);
return this;
}
@Override
public BodyBuilder ifModifiedSince(Instant ifModifiedSince) {
this.headers.setIfModifiedSince(ifModifiedSince);
return this;
}
@Override
public BodyBuilder ifModifiedSince(long ifModifiedSince) {
this.headers.setIfModifiedSince(ifModifiedSince);

View File

@@ -350,6 +350,26 @@ public class ResponseEntity<T> extends HttpEntity<T> {
*/
B eTag(String etag);
/**
* Set the time the resource was last changed, as specified by the
* {@code Last-Modified} header.
* @param lastModified the last modified date
* @return this builder
* @since 5.1.4
* @see HttpHeaders#setLastModified(ZonedDateTime)
*/
B lastModified(ZonedDateTime lastModified);
/**
* Set the time the resource was last changed, as specified by the
* {@code Last-Modified} header.
* @param lastModified the last modified date
* @return this builder
* @since 5.1.4
* @see HttpHeaders#setLastModified(Instant)
*/
B lastModified(Instant lastModified);
/**
* Set the time the resource was last changed, as specified by the
* {@code Last-Modified} header.
@@ -361,26 +381,6 @@ public class ResponseEntity<T> extends HttpEntity<T> {
*/
B lastModified(long lastModified);
/**
* Set the time the resource was last changed, as specified by the
* {@code Last-Modified} header.
* @param lastModified the last modified date
* @return this builder
* @since 5.1.4
* @see HttpHeaders#setLastModified(long)
*/
B lastModified(Instant lastModified);
/**
* Set the time the resource was last changed, as specified by the
* {@code Last-Modified} header.
* @param lastModified the last modified date
* @return this builder
* @since 5.1.4
* @see HttpHeaders#setLastModified(long)
*/
B lastModified(ZonedDateTime lastModified);
/**
* Set the location of a resource, as specified by the {@code Location} header.
* @param location the location
@@ -512,7 +512,7 @@ public class ResponseEntity<T> extends HttpEntity<T> {
}
@Override
public BodyBuilder lastModified(long date) {
public BodyBuilder lastModified(ZonedDateTime date) {
this.headers.setLastModified(date);
return this;
}
@@ -524,7 +524,7 @@ public class ResponseEntity<T> extends HttpEntity<T> {
}
@Override
public BodyBuilder lastModified(ZonedDateTime date) {
public BodyBuilder lastModified(long date) {
this.headers.setLastModified(date);
return this;
}