Skip to content

Commit 90d768b

Browse files
committed
Overloaded convenience setters: setCacheControl(CacheControl), setExpires(ZonedDateTime)
Issue: SPR-16562
1 parent 82515a3 commit 90d768b

File tree

2 files changed

+75
-42
lines changed

2 files changed

+75
-42
lines changed

spring-web/src/main/java/org/springframework/http/HttpHeaders.java

+47-30
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@
4848
import org.springframework.util.MultiValueMap;
4949
import org.springframework.util.StringUtils;
5050

51-
5251
/**
5352
* Represents HTTP request and response headers, mapping string header names to a list of string values.
5453
*
@@ -472,8 +471,8 @@ public void setAcceptLanguage(List<Locale.LanguageRange> languages) {
472471
* {@link #getAcceptLanguageAsLocales()} or if you need to filter based on
473472
* a list of supported locales you can pass the returned list to
474473
* {@link Locale#filter(List, Collection)}.
475-
* @since 5.0
476474
* @throws IllegalArgumentException if the value cannot be converted to a language range
475+
* @since 5.0
477476
*/
478477
public List<Locale.LanguageRange> getAcceptLanguage() {
479478
String value = getFirst(ACCEPT_LANGUAGE);
@@ -494,8 +493,8 @@ public void setAcceptLanguageAsLocales(List<Locale> locales) {
494493
* A variant of {@link #getAcceptLanguage()} that converts each
495494
* {@link java.util.Locale.LanguageRange} to a {@link Locale}.
496495
* @return the locales or an empty list
497-
* @since 5.0
498496
* @throws IllegalArgumentException if the value cannot be converted to a locale
497+
* @since 5.0
499498
*/
500499
public List<Locale> getAcceptLanguageAsLocales() {
501500
List<Locale.LanguageRange> ranges = getAcceptLanguage();
@@ -711,6 +710,15 @@ public Set<HttpMethod> getAllow() {
711710
}
712711
}
713712

713+
/**
714+
* Set a configured {@link CacheControl} instance as the
715+
* new value of the {@code Cache-Control} header.
716+
* @since 5.0.5
717+
*/
718+
public void setCacheControl(CacheControl cacheControl) {
719+
set(CACHE_CONTROL, cacheControl.getHeaderValue());
720+
}
721+
714722
/**
715723
* Set the (new) value of the {@code Cache-Control} header.
716724
*/
@@ -907,6 +915,15 @@ public String getETag() {
907915
return getFirst(ETAG);
908916
}
909917

918+
/**
919+
* Set the duration after which the message is no longer valid,
920+
* as specified by the {@code Expires} header.
921+
* @since 5.0.5
922+
*/
923+
public void setExpires(ZonedDateTime expires) {
924+
setZonedDateTime(EXPIRES, expires);
925+
}
926+
910927
/**
911928
* Set the date and time at which the message is no longer valid,
912929
* as specified by the {@code Expires} header.
@@ -932,13 +949,16 @@ public long getExpires() {
932949
* Set the (new) value of the {@code Host} header.
933950
* <p>If the given {@linkplain InetSocketAddress#getPort() port} is {@code 0},
934951
* the host header will only contain the
935-
* {@linkplain InetSocketAddress#getHostString() hostname}.
952+
* {@linkplain InetSocketAddress#getHostString() host name}.
936953
* @since 5.0
937954
*/
938955
public void setHost(@Nullable InetSocketAddress host) {
939956
if (host != null) {
940-
String value = (host.getPort() != 0 ?
941-
String.format("%s:%d", host.getHostString(), host.getPort()) : host.getHostString());
957+
String value = host.getHostString();
958+
int port = host.getPort();
959+
if (port != 0) {
960+
value = value + ":" + port;
961+
}
942962
set(HOST, value);
943963
}
944964
else {
@@ -958,28 +978,25 @@ public InetSocketAddress getHost() {
958978
if (value == null) {
959979
return null;
960980
}
961-
final int idx;
962-
if (value.startsWith("[")) {
963-
idx = value.indexOf(':', value.indexOf(']'));
964-
} else {
965-
idx = value.lastIndexOf(':');
966-
}
967-
String hostname = null;
981+
982+
String host = null;
968983
int port = 0;
969-
if (idx != -1 && idx < value.length() - 1) {
970-
hostname = value.substring(0, idx);
971-
String portString = value.substring(idx + 1);
984+
int separator = (value.startsWith("[") ? value.indexOf(':', value.indexOf(']')) : value.lastIndexOf(':'));
985+
if (separator != -1) {
986+
host = value.substring(0, separator);
987+
String portString = value.substring(separator + 1);
972988
try {
973989
port = Integer.parseInt(portString);
974990
}
975991
catch (NumberFormatException ex) {
976-
// ignored
992+
// ignore
977993
}
978994
}
979-
if (hostname == null) {
980-
hostname = value;
995+
996+
if (host == null) {
997+
host = value;
981998
}
982-
return InetSocketAddress.createUnresolved(hostname, port);
999+
return InetSocketAddress.createUnresolved(host, port);
9831000
}
9841001

9851002
/**
@@ -1192,23 +1209,23 @@ public List<String> getVary() {
11921209
* Set the given date under the given header name after formatting it as a string
11931210
* using the RFC-1123 date-time formatter. The equivalent of
11941211
* {@link #set(String, String)} but for date headers.
1195-
* @since 3.2.4
1196-
* @see #setZonedDateTime(String, ZonedDateTime)
1212+
* @since 5.0
11971213
*/
1198-
public void setDate(String headerName, long date) {
1199-
Instant instant = Instant.ofEpochMilli(date);
1200-
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(instant, GMT);
1201-
set(headerName, DATE_FORMATTERS[0].format(zonedDateTime));
1214+
public void setZonedDateTime(String headerName, ZonedDateTime date) {
1215+
set(headerName, DATE_FORMATTERS[0].format(date));
12021216
}
12031217

12041218
/**
12051219
* Set the given date under the given header name after formatting it as a string
12061220
* using the RFC-1123 date-time formatter. The equivalent of
12071221
* {@link #set(String, String)} but for date headers.
1208-
* @since 5.0
1222+
* @since 3.2.4
1223+
* @see #setZonedDateTime(String, ZonedDateTime)
12091224
*/
1210-
public void setZonedDateTime(String headerName, ZonedDateTime date) {
1211-
set(headerName, DATE_FORMATTERS[0].format(date));
1225+
public void setDate(String headerName, long date) {
1226+
Instant instant = Instant.ofEpochMilli(date);
1227+
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(instant, GMT);
1228+
set(headerName, DATE_FORMATTERS[0].format(zonedDateTime));
12121229
}
12131230

12141231
/**
@@ -1549,7 +1566,7 @@ public String toString() {
15491566
* Return a {@code HttpHeaders} object that can only be read, not written to.
15501567
*/
15511568
public static HttpHeaders readOnlyHttpHeaders(HttpHeaders headers) {
1552-
return headers.readOnly ? headers : new HttpHeaders(headers, true);
1569+
return (headers.readOnly ? headers : new HttpHeaders(headers, true));
15531570
}
15541571

15551572
}

spring-web/src/test/java/org/springframework/http/HttpHeadersTests.java

+28-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
2121
import java.net.URISyntaxException;
2222
import java.nio.charset.Charset;
2323
import java.nio.charset.StandardCharsets;
24+
import java.time.DateTimeException;
2425
import java.time.ZoneId;
2526
import java.time.ZonedDateTime;
2627
import java.util.ArrayList;
@@ -37,20 +38,16 @@
3738
import org.junit.Test;
3839

3940
import static java.time.format.DateTimeFormatter.*;
40-
import static org.hamcrest.Matchers.is;
41-
import static org.junit.Assert.assertEquals;
42-
import static org.junit.Assert.assertFalse;
43-
import static org.junit.Assert.assertNotNull;
44-
import static org.junit.Assert.assertNull;
45-
import static org.junit.Assert.assertThat;
46-
import static org.junit.Assert.assertTrue;
41+
import static org.hamcrest.Matchers.*;
42+
import static org.junit.Assert.*;
4743

4844
/**
4945
* Unit tests for {@link org.springframework.http.HttpHeaders}.
5046
*
5147
* @author Arjen Poutsma
5248
* @author Sebastien Deleuze
5349
* @author Brian Clozel
50+
* @author Juergen Hoeller
5451
*/
5552
public class HttpHeadersTests {
5653

@@ -284,7 +281,7 @@ public void lastModified() {
284281
}
285282

286283
@Test
287-
public void expires() {
284+
public void expiresLong() {
288285
Calendar calendar = new GregorianCalendar(2008, 11, 18, 11, 20);
289286
calendar.setTimeZone(TimeZone.getTimeZone("CET"));
290287
long date = calendar.getTimeInMillis();
@@ -293,6 +290,19 @@ public void expires() {
293290
assertEquals("Invalid Expires header", "Thu, 18 Dec 2008 10:20:00 GMT", headers.getFirst("expires"));
294291
}
295292

293+
@Test
294+
public void expiresZonedDateTime() {
295+
ZonedDateTime zonedDateTime = ZonedDateTime.of(2008, 12, 18, 10, 20, 0, 0, ZoneId.of("GMT"));
296+
headers.setExpires(zonedDateTime);
297+
assertEquals("Invalid Expires header", zonedDateTime.toInstant().toEpochMilli(), headers.getExpires());
298+
assertEquals("Invalid Expires header", "Thu, 18 Dec 2008 10:20:00 GMT", headers.getFirst("expires"));
299+
}
300+
301+
@Test(expected = DateTimeException.class) // SPR-16560
302+
public void expiresLargeDate() {
303+
headers.setExpires(Long.MAX_VALUE);
304+
}
305+
296306
@Test // SPR-10648 (example is from INT-3063)
297307
public void expiresInvalidDate() {
298308
headers.set("Expires", "-1");
@@ -332,9 +342,15 @@ public void pragma() {
332342

333343
@Test
334344
public void cacheControl() {
335-
String cacheControl = "no-cache";
336-
headers.setCacheControl(cacheControl);
337-
assertEquals("Invalid Cache-Control header", cacheControl, headers.getCacheControl());
345+
headers.setCacheControl("no-cache");
346+
assertEquals("Invalid Cache-Control header", "no-cache", headers.getCacheControl());
347+
assertEquals("Invalid Cache-Control header", "no-cache", headers.getFirst("cache-control"));
348+
}
349+
350+
@Test
351+
public void cacheControlBuilder() {
352+
headers.setCacheControl(CacheControl.noCache());
353+
assertEquals("Invalid Cache-Control header", "no-cache", headers.getCacheControl());
338354
assertEquals("Invalid Cache-Control header", "no-cache", headers.getFirst("cache-control"));
339355
}
340356

0 commit comments

Comments
 (0)