Skip to content

Commit 9f22e0c

Browse files
committed
Polish "Make CacheControl immutable"
See gh-33366
1 parent c3ab9bb commit 9f22e0c

File tree

1 file changed

+69
-62
lines changed

1 file changed

+69
-62
lines changed

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

+69-62
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 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.
@@ -23,7 +23,8 @@
2323
import org.springframework.util.StringUtils;
2424

2525
/**
26-
* A builder for creating "Cache-Control" HTTP response headers.
26+
* A builder for creating "Cache-Control" HTTP response headers. As of Spring
27+
* Framework 6.2, this class is immutable.
2728
*
2829
* <p>Adding Cache-Control directives to HTTP responses can significantly improve the client
2930
* experience when interacting with a web application. This builder creates opinionated
@@ -51,9 +52,7 @@
5152
*/
5253
public class CacheControl {
5354

54-
private static final CacheControl EMPTY = new CacheControl(null, false, false, false,
55-
false, false, false, false, null, null,
56-
null, false);
55+
private static final CacheControl EMPTY = new CacheControl();
5756

5857
@Nullable
5958
private final Duration maxAge;
@@ -83,10 +82,18 @@ public class CacheControl {
8382

8483
private final boolean immutable;
8584

85+
/**
86+
* Create an empty CacheControl instance.
87+
* @see #empty()
88+
*/
89+
protected CacheControl() {
90+
this(null, false, false, false, false, false, false, false, null, null, null, false);
91+
}
92+
8693
private CacheControl(@Nullable Duration maxAge, boolean noCache, boolean noStore,
87-
boolean mustRevalidate, boolean noTransform, boolean cachePublic,
88-
boolean cachePrivate, boolean proxyRevalidate, @Nullable Duration staleWhileRevalidate,
89-
@Nullable Duration staleIfError, @Nullable Duration sMaxAge, boolean immutable) {
94+
boolean mustRevalidate, boolean noTransform, boolean cachePublic,
95+
boolean cachePrivate, boolean proxyRevalidate, @Nullable Duration staleWhileRevalidate,
96+
@Nullable Duration staleIfError, @Nullable Duration sMaxAge, boolean immutable) {
9097
this.maxAge = maxAge;
9198
this.noCache = noCache;
9299
this.noStore = noStore;
@@ -105,14 +112,14 @@ private CacheControl(@Nullable Duration maxAge, boolean noCache, boolean noStore
105112
* Return an empty directive.
106113
* <p>This is well suited for using other optional directives without "max-age",
107114
* "no-cache" or "no-store".
108-
* @return {@code this}, to facilitate method chaining
115+
* @return en empty directive
109116
*/
110117
public static CacheControl empty() {
111118
return EMPTY;
112119
}
113120

114121
/**
115-
* Add a "max-age=" directive.
122+
* Return a "max-age=" directive.
116123
* <p>This directive is well suited for publicly caching resources, knowing that
117124
* they won't change within the configured amount of time. Additional directives
118125
* can be also used, in case resources shouldn't be cached ({@link #cachePrivate()})
@@ -122,7 +129,7 @@ public static CacheControl empty() {
122129
* directive should be set ({@link #mustRevalidate()}
123130
* @param maxAge the maximum time the response should be cached
124131
* @param unit the time unit of the {@code maxAge} argument
125-
* @return {@code this}, to facilitate method chaining
132+
* @return a CacheControl instance with a "max-age" directive
126133
* @see #maxAge(Duration)
127134
* @see <a href="https://tools.ietf.org/html/rfc7234#section-5.2.2.8">rfc7234 section 5.2.2.8</a>
128135
*/
@@ -131,7 +138,7 @@ public static CacheControl maxAge(long maxAge, TimeUnit unit) {
131138
}
132139

133140
/**
134-
* Add a "max-age=" directive.
141+
* Return a "max-age=" directive.
135142
* <p>This directive is well suited for publicly caching resources, knowing that
136143
* they won't change within the configured amount of time. Additional directives
137144
* can be also used, in case resources shouldn't be cached ({@link #cachePrivate()})
@@ -140,120 +147,120 @@ public static CacheControl maxAge(long maxAge, TimeUnit unit) {
140147
* become stale (i.e. the "max-age" delay is passed), the "must-revalidate"
141148
* directive should be set ({@link #mustRevalidate()}
142149
* @param maxAge the maximum time the response should be cached
143-
* @return {@code this}, to facilitate method chaining
150+
* @return a CacheControl instance with a "max-age" directive
144151
* @since 5.2
145152
* @see <a href="https://tools.ietf.org/html/rfc7234#section-5.2.2.8">rfc7234 section 5.2.2.8</a>
146153
*/
147154
public static CacheControl maxAge(Duration maxAge) {
148155
return new CacheControl(maxAge, false, false, false, false, false, false, false,
149-
null, null, null, false);
156+
null, null, null, false);
150157
}
151158

152159
/**
153-
* Add a "no-cache" directive.
160+
* Return a "no-cache" directive.
154161
* <p>This directive is well suited for telling caches that the response
155162
* can be reused only if the client revalidates it with the server.
156163
* This directive won't disable cache altogether and may result with clients
157164
* sending conditional requests (with "ETag", "If-Modified-Since" headers)
158165
* and the server responding with "304 - Not Modified" status.
159166
* <p>In order to disable caching and minimize requests/responses exchanges,
160167
* the {@link #noStore()} directive should be used instead of {@code #noCache()}.
161-
* @return {@code this}, to facilitate method chaining
168+
* @return a CacheControl instance with a "no-cache" directive
162169
* @see <a href="https://tools.ietf.org/html/rfc7234#section-5.2.2.2">rfc7234 section 5.2.2.2</a>
163170
*/
164171
public static CacheControl noCache() {
165172
return new CacheControl(null, true, false, false, false, false, false, false,
166-
null, null, null, false);
173+
null, null, null, false);
167174
}
168175

169176
/**
170-
* Add a "no-store" directive.
177+
* Return a "no-store" directive.
171178
* <p>This directive is well suited for preventing caches (browsers and proxies)
172179
* to cache the content of responses.
173-
* @return {@code this}, to facilitate method chaining
180+
* @return a CacheControl instance with a "no-store" directive
174181
* @see <a href="https://tools.ietf.org/html/rfc7234#section-5.2.2.3">rfc7234 section 5.2.2.3</a>
175182
*/
176183
public static CacheControl noStore() {
177184
return new CacheControl(null, false, true, false, false, false, false, false,
178-
null, null, null, false);
185+
null, null, null, false);
179186
}
180187

181188

182189
/**
183-
* Add a "must-revalidate" directive.
190+
* Return a new instance with an additional "must-revalidate" directive.
184191
* <p>This directive indicates that once it has become stale, a cache MUST NOT
185192
* use the response to satisfy subsequent requests without successful validation
186193
* on the origin server.
187-
* @return {@code this}, to facilitate method chaining
194+
* @return a new CacheControl instance with an additional "must-revalidate" directive
188195
* @see <a href="https://tools.ietf.org/html/rfc7234#section-5.2.2.1">rfc7234 section 5.2.2.1</a>
189196
*/
190197
public CacheControl mustRevalidate() {
191198
return new CacheControl(this.maxAge, this.noCache, this.noStore, true, this.noTransform,
192-
this.cachePublic, this.cachePrivate, this.proxyRevalidate, this.staleWhileRevalidate,
193-
this.staleIfError, this.sMaxAge, this.immutable);
199+
this.cachePublic, this.cachePrivate, this.proxyRevalidate, this.staleWhileRevalidate,
200+
this.staleIfError, this.sMaxAge, this.immutable);
194201
}
195202

196203
/**
197-
* Add a "no-transform" directive.
204+
* Return a new instance with an additional "no-transform" directive.
198205
* <p>This directive indicates that intermediaries (caches and others) should
199206
* not transform the response content. This can be useful to force caches and
200207
* CDNs not to automatically gzip or optimize the response content.
201-
* @return {@code this}, to facilitate method chaining
208+
* @return a new CacheControl instance with an additional "no-transform" directive
202209
* @see <a href="https://tools.ietf.org/html/rfc7234#section-5.2.2.4">rfc7234 section 5.2.2.4</a>
203210
*/
204211
public CacheControl noTransform() {
205212
return new CacheControl(this.maxAge, this.noCache, this.noStore, this.mustRevalidate, true,
206-
this.cachePublic, this.cachePrivate, this.proxyRevalidate, this.staleWhileRevalidate,
207-
this.staleIfError, this.sMaxAge, this.immutable);
213+
this.cachePublic, this.cachePrivate, this.proxyRevalidate, this.staleWhileRevalidate,
214+
this.staleIfError, this.sMaxAge, this.immutable);
208215
}
209216

210217
/**
211-
* Add a "public" directive.
218+
* Return a new instance with an additional "public" directive.
212219
* <p>This directive indicates that any cache MAY store the response,
213220
* even if the response would normally be non-cacheable or cacheable
214221
* only within a private cache.
215-
* @return {@code this}, to facilitate method chaining
222+
* @return a new CacheControl instance with an additional "public" directive
216223
* @see <a href="https://tools.ietf.org/html/rfc7234#section-5.2.2.5">rfc7234 section 5.2.2.5</a>
217224
*/
218225
public CacheControl cachePublic() {
219226
return new CacheControl(this.maxAge, this.noCache, this.noStore, this.mustRevalidate, this.noTransform,
220-
true, this.cachePrivate, this.proxyRevalidate, this.staleWhileRevalidate,
221-
this.staleIfError, this.sMaxAge, this.immutable);
227+
true, this.cachePrivate, this.proxyRevalidate, this.staleWhileRevalidate,
228+
this.staleIfError, this.sMaxAge, this.immutable);
222229
}
223230

224231
/**
225-
* Add a "private" directive.
232+
* Return a new instance with an additional "private" directive.
226233
* <p>This directive indicates that the response message is intended
227234
* for a single user and MUST NOT be stored by a shared cache.
228-
* @return {@code this}, to facilitate method chaining
235+
* @return a new CacheControl instance with an additional "private" directive
229236
* @see <a href="https://tools.ietf.org/html/rfc7234#section-5.2.2.6">rfc7234 section 5.2.2.6</a>
230237
*/
231238
public CacheControl cachePrivate() {
232239
return new CacheControl(this.maxAge, this.noCache, this.noStore, this.mustRevalidate, this.noTransform,
233-
this.cachePublic, true, this.proxyRevalidate, this.staleWhileRevalidate,
234-
this.staleIfError, this.sMaxAge, this.immutable);
240+
this.cachePublic, true, this.proxyRevalidate, this.staleWhileRevalidate,
241+
this.staleIfError, this.sMaxAge, this.immutable);
235242
}
236243

237244
/**
238-
* Add a "proxy-revalidate" directive.
245+
* Return a new instance with an additional "proxy-revalidate" directive.
239246
* <p>This directive has the same meaning as the "must-revalidate" directive,
240247
* except that it does not apply to private caches (i.e. browsers, HTTP clients).
241-
* @return {@code this}, to facilitate method chaining
248+
* @return a new CacheControl instance with an additional "proxy-revalidate" directive
242249
* @see <a href="https://tools.ietf.org/html/rfc7234#section-5.2.2.7">rfc7234 section 5.2.2.7</a>
243250
*/
244251
public CacheControl proxyRevalidate() {
245252
return new CacheControl(this.maxAge, this.noCache, this.noStore, this.mustRevalidate, this.noTransform,
246-
this.cachePublic, this.cachePrivate, true, this.staleWhileRevalidate,
247-
this.staleIfError, this.sMaxAge, this.immutable);
253+
this.cachePublic, this.cachePrivate, true, this.staleWhileRevalidate,
254+
this.staleIfError, this.sMaxAge, this.immutable);
248255
}
249256

250257
/**
251-
* Add an "s-maxage" directive.
258+
* Return a new instance with an additional "s-maxage" directive.
252259
* <p>This directive indicates that, in shared caches, the maximum age specified
253260
* by this directive overrides the maximum age specified by other directives.
254261
* @param sMaxAge the maximum time the response should be cached
255262
* @param unit the time unit of the {@code sMaxAge} argument
256-
* @return {@code this}, to facilitate method chaining
263+
* @return a new CacheControl instance with an additional "s-maxage" directive
257264
* @see #sMaxAge(Duration)
258265
* @see <a href="https://tools.ietf.org/html/rfc7234#section-5.2.2.9">rfc7234 section 5.2.2.9</a>
259266
*/
@@ -262,30 +269,30 @@ public CacheControl sMaxAge(long sMaxAge, TimeUnit unit) {
262269
}
263270

264271
/**
265-
* Add an "s-maxage" directive.
272+
* Return a new instance with an additional "s-maxage" directive.
266273
* <p>This directive indicates that, in shared caches, the maximum age specified
267274
* by this directive overrides the maximum age specified by other directives.
268275
* @param sMaxAge the maximum time the response should be cached
269-
* @return {@code this}, to facilitate method chaining
276+
* @return a new CacheControl instance with an additional "s-maxage" directive
270277
* @since 5.2
271278
* @see <a href="https://tools.ietf.org/html/rfc7234#section-5.2.2.9">rfc7234 section 5.2.2.9</a>
272279
*/
273280
public CacheControl sMaxAge(Duration sMaxAge) {
274281
return new CacheControl(this.maxAge, this.noCache, this.noStore, this.mustRevalidate, this.noTransform,
275-
this.cachePublic, this.cachePrivate, this.proxyRevalidate, this.staleWhileRevalidate,
276-
this.staleIfError, sMaxAge, this.immutable);
282+
this.cachePublic, this.cachePrivate, this.proxyRevalidate, this.staleWhileRevalidate,
283+
this.staleIfError, sMaxAge, this.immutable);
277284
}
278285

279286
/**
280-
* Add a "stale-while-revalidate" directive.
287+
* Return a new instance with an additional "stale-while-revalidate" directive.
281288
* <p>This directive indicates that caches MAY serve the response in which it
282289
* appears after it becomes stale, up to the indicated number of seconds.
283290
* If a cached response is served stale due to the presence of this extension,
284291
* the cache SHOULD attempt to revalidate it while still serving stale responses
285292
* (i.e. without blocking).
286293
* @param staleWhileRevalidate the maximum time the response should be used while being revalidated
287294
* @param unit the time unit of the {@code staleWhileRevalidate} argument
288-
* @return {@code this}, to facilitate method chaining
295+
* @return a new CacheControl instance with an additional "stale-while-revalidate" directive
289296
* @see #staleWhileRevalidate(Duration)
290297
* @see <a href="https://tools.ietf.org/html/rfc5861#section-3">rfc5861 section 3</a>
291298
*/
@@ -294,30 +301,30 @@ public CacheControl staleWhileRevalidate(long staleWhileRevalidate, TimeUnit uni
294301
}
295302

296303
/**
297-
* Add a "stale-while-revalidate" directive.
304+
* Return a new instance with an additional "stale-while-revalidate" directive.
298305
* <p>This directive indicates that caches MAY serve the response in which it
299306
* appears after it becomes stale, up to the indicated number of seconds.
300307
* If a cached response is served stale due to the presence of this extension,
301308
* the cache SHOULD attempt to revalidate it while still serving stale responses
302309
* (i.e. without blocking).
303310
* @param staleWhileRevalidate the maximum time the response should be used while being revalidated
304-
* @return {@code this}, to facilitate method chaining
311+
* @return a new CacheControl instance with an additional "stale-while-revalidate" directive
305312
* @since 5.2
306313
* @see <a href="https://tools.ietf.org/html/rfc5861#section-3">rfc5861 section 3</a>
307314
*/
308315
public CacheControl staleWhileRevalidate(Duration staleWhileRevalidate) {
309316
return new CacheControl(this.maxAge, this.noCache, this.noStore, this.mustRevalidate, this.noTransform,
310-
this.cachePublic, this.cachePrivate, this.proxyRevalidate, staleWhileRevalidate,
311-
this.staleIfError, this.sMaxAge, this.immutable);
317+
this.cachePublic, this.cachePrivate, this.proxyRevalidate, staleWhileRevalidate,
318+
this.staleIfError, this.sMaxAge, this.immutable);
312319
}
313320

314321
/**
315-
* Add a "stale-if-error" directive.
322+
* Return a new instance with an additional "stale-if-error" directive.
316323
* <p>This directive indicates that when an error is encountered, a cached stale response
317324
* MAY be used to satisfy the request, regardless of other freshness information.
318325
* @param staleIfError the maximum time the response should be used when errors are encountered
319326
* @param unit the time unit of the {@code staleIfError} argument
320-
* @return {@code this}, to facilitate method chaining
327+
* @return a new CacheControl instance with an additional "stale-if-error" directive
321328
* @see #staleIfError(Duration)
322329
* @see <a href="https://tools.ietf.org/html/rfc5861#section-4">rfc5861 section 4</a>
323330
*/
@@ -326,34 +333,34 @@ public CacheControl staleIfError(long staleIfError, TimeUnit unit) {
326333
}
327334

328335
/**
329-
* Add a "stale-if-error" directive.
336+
* Return a new instance with an additional "stale-if-error" directive.
330337
* <p>This directive indicates that when an error is encountered, a cached stale response
331338
* MAY be used to satisfy the request, regardless of other freshness information.
332339
* @param staleIfError the maximum time the response should be used when errors are encountered
333-
* @return {@code this}, to facilitate method chaining
340+
* @return a new CacheControl instance with an additional "stale-if-error" directive
334341
* @since 5.2
335342
* @see <a href="https://tools.ietf.org/html/rfc5861#section-4">rfc5861 section 4</a>
336343
*/
337344
public CacheControl staleIfError(Duration staleIfError) {
338345
return new CacheControl(this.maxAge, this.noCache, this.noStore, this.mustRevalidate, this.noTransform,
339-
this.cachePublic, this.cachePrivate, this.proxyRevalidate, this.staleWhileRevalidate,
340-
staleIfError, this.sMaxAge, this.immutable);
346+
this.cachePublic, this.cachePrivate, this.proxyRevalidate, this.staleWhileRevalidate,
347+
staleIfError, this.sMaxAge, this.immutable);
341348
}
342349

343350
/**
344-
* Add an "immutable" directive.
351+
* Return a new instance with an additional "immutable" directive.
345352
* <p>This directive indicates that the origin server will not update the
346353
* representation of that resource during the freshness lifetime of the response.
347354
* Adding a {@link #maxAge(Duration) max-age} directive is strongly advised
348355
* to enforce the actual freshness lifetime.
349-
* @return {@code this}, to facilitate method chaining
356+
* @return a new CacheControl instance with an additional "immutable" directive
350357
* @since 6.0.5
351358
* @see <a href="https://tools.ietf.org/html/rfc8246">rfc8246</a>
352359
*/
353360
public CacheControl immutable() {
354361
return new CacheControl(this.maxAge, this.noCache, this.noStore, this.mustRevalidate, this.noTransform,
355-
this.cachePublic, this.cachePrivate, this.proxyRevalidate, this.staleWhileRevalidate,
356-
this.staleIfError, this.sMaxAge, true);
362+
this.cachePublic, this.cachePrivate, this.proxyRevalidate, this.staleWhileRevalidate,
363+
this.staleIfError, this.sMaxAge, true);
357364
}
358365

359366
/**

0 commit comments

Comments
 (0)