diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ResourceProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ResourceProperties.java index e799775b5bf..ba5d830a217 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ResourceProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ResourceProperties.java @@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure.web; import java.time.Duration; import java.time.temporal.ChronoUnit; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.bind.convert.DefaultDurationUnit; @@ -48,16 +49,16 @@ public class ResourceProperties { private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS; /** - * Cache period for the resources served by the resource handler. - * If a duration suffix is not specified, seconds will be used. - * Can be overridden by the {@code cache-control} property. + * Cache period for the resources served by the resource handler. If a duration suffix + * is not specified, seconds will be used. Can be overridden by the 'cache-control' + * property. */ @DefaultDurationUnit(ChronoUnit.SECONDS) private Duration cachePeriod; /** - * Cache control HTTP headers, only allows valid directive combinations. - * Overrides the {@code cache-period} property. + * Cache control HTTP headers, only allows valid directive combinations. Overrides the + * 'cache-period' property. */ private CacheControlProperties cacheControl = new CacheControlProperties(); @@ -145,9 +146,8 @@ public class ResourceProperties { /** * Return whether the resource chain is enabled. Return {@code null} if no * specific settings are present. - * - * @return whether the resource chain is enabled or {@code null} if no specified settings are - * present. + * @return whether the resource chain is enabled or {@code null} if no specified + * settings are present. */ public Boolean getEnabled() { return getEnabled(getStrategy().getFixed().isEnabled(), @@ -225,7 +225,7 @@ public class ResourceProperties { /** * Comma-separated list of patterns to apply to the Version Strategy. */ - private String[] paths = new String[]{"/**"}; + private String[] paths = new String[] { "/**" }; public boolean isEnabled() { return this.enabled; @@ -258,7 +258,7 @@ public class ResourceProperties { /** * Comma-separated list of patterns to apply to the Version Strategy. */ - private String[] paths = new String[]{"/**"}; + private String[] paths = new String[] { "/**" }; /** * Version string to use for the Version Strategy. @@ -297,15 +297,15 @@ public class ResourceProperties { public static class CacheControlProperties { /** - * Maximum time the response should be cached, - * in seconds if no duration suffix is not specified. + * Maximum time the response should be cached, in seconds if no duration suffix is + * not specified. */ @DefaultDurationUnit(ChronoUnit.SECONDS) private Duration maxAge; /** - * Indicate that the cached response can be reused only - * if re-validated with the server. + * Indicate that the cached response can be reused only if re-validated with the + * server. */ private Boolean noCache; @@ -315,14 +315,14 @@ public class ResourceProperties { private Boolean noStore; /** - * Indicate that once it has become stale, a cache must not use - * the response without re-validating it with the server. + * Indicate that once it has become stale, a cache must not use the response + * without re-validating it with the server. */ private Boolean mustRevalidate; /** - * Indicate intermediaries (caches and others) that they should - * not transform the response content. + * Indicate intermediaries (caches and others) that they should not transform the + * response content. */ private Boolean noTransform; @@ -332,34 +332,34 @@ public class ResourceProperties { private Boolean cachePublic; /** - * Indicate that the response message is intended for a single user - * and must not be stored by a shared cache. + * Indicate that the response message is intended for a single user and must not + * be stored by a shared cache. */ private Boolean cachePrivate; /** - * Same meaning as the "must-revalidate" directive, - * except that it does not apply to private caches. + * Same meaning as the "must-revalidate" directive, except that it does not apply + * to private caches. */ private Boolean proxyRevalidate; /** - * Maximum time the response can be served after it becomes stale, - * in seconds if no duration suffix is not specified. + * Maximum time the response can be served after it becomes stale, in seconds if + * no duration suffix is not specified. */ @DefaultDurationUnit(ChronoUnit.SECONDS) private Duration staleWhileRevalidate; /** - * Maximum time the response may be used when errors are encountered, - * in seconds if no duration suffix is not specified. + * Maximum time the response may be used when errors are encountered, in seconds + * if no duration suffix is not specified. */ @DefaultDurationUnit(ChronoUnit.SECONDS) private Duration staleIfError; /** - * Maximum time the response should be cached by shared caches, - * in seconds if no duration suffix is not specified. + * Maximum time the response should be cached by shared caches, in seconds if no + * duration suffix is not specified. */ @DefaultDurationUnit(ChronoUnit.SECONDS) private Duration sMaxAge; @@ -453,44 +453,43 @@ public class ResourceProperties { } public CacheControl toHttpCacheControl() { - CacheControl cc; - if (Boolean.TRUE.equals(this.noStore)) { - cc = CacheControl.noStore(); - } - else if (Boolean.TRUE.equals(this.noCache)) { - cc = CacheControl.noCache(); - } - else if (this.maxAge != null) { - cc = CacheControl.maxAge(this.maxAge.getSeconds(), TimeUnit.SECONDS); - } - else { - cc = CacheControl.empty(); - } - if (Boolean.TRUE.equals(this.mustRevalidate)) { - cc.mustRevalidate(); - } - if (Boolean.TRUE.equals(this.noTransform)) { - cc.noTransform(); - } - if (Boolean.TRUE.equals(this.cachePublic)) { - cc.cachePublic(); - } - if (Boolean.TRUE.equals(this.cachePrivate)) { - cc.cachePrivate(); - } - if (Boolean.TRUE.equals(this.proxyRevalidate)) { - cc.proxyRevalidate(); - } + CacheControl cacheControl = createCacheControl(); + callIfTrue(this.mustRevalidate, cacheControl, CacheControl::mustRevalidate); + callIfTrue(this.noTransform, cacheControl, CacheControl::noTransform); + callIfTrue(this.cachePublic, cacheControl, CacheControl::cachePublic); + callIfTrue(this.cachePrivate, cacheControl, CacheControl::cachePrivate); + callIfTrue(this.proxyRevalidate, cacheControl, CacheControl::proxyRevalidate); if (this.staleWhileRevalidate != null) { - cc.staleWhileRevalidate(this.staleWhileRevalidate.getSeconds(), TimeUnit.SECONDS); + cacheControl.staleWhileRevalidate(this.staleWhileRevalidate.getSeconds(), + TimeUnit.SECONDS); } if (this.staleIfError != null) { - cc.staleIfError(this.staleIfError.getSeconds(), TimeUnit.SECONDS); + cacheControl.staleIfError(this.staleIfError.getSeconds(), + TimeUnit.SECONDS); } if (this.sMaxAge != null) { - cc.sMaxAge(this.sMaxAge.getSeconds(), TimeUnit.SECONDS); + cacheControl.sMaxAge(this.sMaxAge.getSeconds(), TimeUnit.SECONDS); + } + return cacheControl; + } + + private CacheControl createCacheControl() { + if (Boolean.TRUE.equals(this.noStore)) { + return CacheControl.noStore(); + } + if (Boolean.TRUE.equals(this.noCache)) { + return CacheControl.noCache(); + } + if (this.maxAge != null) { + return CacheControl.maxAge(this.maxAge.getSeconds(), TimeUnit.SECONDS); + } + return CacheControl.empty(); + } + + private void callIfTrue(Boolean property, T instance, Consumer call) { + if (Boolean.TRUE.equals(property)) { + call.accept(instance); } - return cc; } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java index 584c00d531a..3fdb9817e76 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java @@ -309,14 +309,15 @@ public class WebMvcAutoConfiguration { return; } Duration cachePeriod = this.resourceProperties.getCachePeriod(); - CacheControl cacheControl = this.resourceProperties.getCacheControl().toHttpCacheControl(); + CacheControl cacheControl = this.resourceProperties.getCacheControl() + .toHttpCacheControl(); if (!registry.hasMappingForPattern("/webjars/**")) { customizeResourceHandlerRegistration( registry.addResourceHandler("/webjars/**") .addResourceLocations( "classpath:/META-INF/resources/webjars/") - .setCachePeriod(getSeconds(cachePeriod)) - .setCacheControl(cacheControl)); + .setCachePeriod(getSeconds(cachePeriod)) + .setCacheControl(cacheControl)); } String staticPathPattern = this.mvcProperties.getStaticPathPattern(); if (!registry.hasMappingForPattern(staticPathPattern)) { @@ -324,8 +325,8 @@ public class WebMvcAutoConfiguration { registry.addResourceHandler(staticPathPattern) .addResourceLocations(getResourceLocations( this.resourceProperties.getStaticLocations())) - .setCachePeriod(getSeconds(cachePeriod)) - .setCacheControl(cacheControl)); + .setCachePeriod(getSeconds(cachePeriod)) + .setCacheControl(cacheControl)); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/ReactiveSessionAutoConfigurationRedisTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/ReactiveSessionAutoConfigurationRedisTests.java index f6281feb393..24d8a04b664 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/ReactiveSessionAutoConfigurationRedisTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/ReactiveSessionAutoConfigurationRedisTests.java @@ -57,7 +57,8 @@ public class ReactiveSessionAutoConfigurationRedisTests this.contextRunner.withPropertyValues("spring.session.store-type=redis") .withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class, RedisReactiveAutoConfiguration.class)) - .run(validateSpringSessionUsesRedis("spring:session:", RedisFlushMode.ON_SAVE)); + .run(validateSpringSessionUsesRedis("spring:session:", + RedisFlushMode.ON_SAVE)); } @Test @@ -67,7 +68,8 @@ public class ReactiveSessionAutoConfigurationRedisTests ReactiveMongoOperationsSessionRepository.class)) .withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class, RedisReactiveAutoConfiguration.class)) - .run(validateSpringSessionUsesRedis("spring:session:", RedisFlushMode.ON_SAVE)); + .run(validateSpringSessionUsesRedis("spring:session:", + RedisFlushMode.ON_SAVE)); } @Test diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ResourcePropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ResourcePropertiesTests.java index 564423edc57..334c214a006 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ResourcePropertiesTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ResourcePropertiesTests.java @@ -24,6 +24,7 @@ import org.junit.rules.ExpectedException; import org.springframework.boot.autoconfigure.web.ResourceProperties.CacheControlProperties; import org.springframework.boot.testsupport.assertj.Matched; +import org.springframework.http.CacheControl; import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.CoreMatchers.endsWith; @@ -78,42 +79,42 @@ public class ResourcePropertiesTests { @Test public void emptyCacheControl() { - CacheControlProperties cacheControl = new CacheControlProperties(); - this.properties.setCacheControl(cacheControl); - assertThat(this.properties.getCacheControl().toHttpCacheControl().getHeaderValue()).isNull(); + CacheControlProperties cacheControlProperties = new CacheControlProperties(); + this.properties.setCacheControl(cacheControlProperties); + CacheControl cacheControl = this.properties.getCacheControl() + .toHttpCacheControl(); + assertThat(cacheControl.getHeaderValue()).isNull(); } @Test public void cacheControlAllPropertiesSet() { - CacheControlProperties cacheControl = new CacheControlProperties(); - cacheControl.setMaxAge(Duration.ofSeconds(4)); - cacheControl.setCachePrivate(true); - cacheControl.setCachePublic(true); - cacheControl.setMustRevalidate(true); - cacheControl.setNoTransform(true); - cacheControl.setProxyRevalidate(true); - cacheControl.setsMaxAge(Duration.ofSeconds(5)); - cacheControl.setStaleIfError(Duration.ofSeconds(6)); - cacheControl.setStaleWhileRevalidate(Duration.ofSeconds(7)); - this.properties.setCacheControl(cacheControl); - assertThat(this.properties.getCacheControl().toHttpCacheControl().getHeaderValue()).isEqualTo( - "max-age=4, must-revalidate, no-transform, public, private, proxy-revalidate," + - " s-maxage=5, stale-if-error=6, stale-while-revalidate=7"); + CacheControlProperties cacheControlProperties = new CacheControlProperties(); + cacheControlProperties.setMaxAge(Duration.ofSeconds(4)); + cacheControlProperties.setCachePrivate(true); + cacheControlProperties.setCachePublic(true); + cacheControlProperties.setMustRevalidate(true); + cacheControlProperties.setNoTransform(true); + cacheControlProperties.setProxyRevalidate(true); + cacheControlProperties.setsMaxAge(Duration.ofSeconds(5)); + cacheControlProperties.setStaleIfError(Duration.ofSeconds(6)); + cacheControlProperties.setStaleWhileRevalidate(Duration.ofSeconds(7)); + this.properties.setCacheControl(cacheControlProperties); + CacheControl cacheControl = this.properties.getCacheControl() + .toHttpCacheControl(); + assertThat(cacheControl.getHeaderValue()).isEqualTo( + "max-age=4, must-revalidate, no-transform, public, private, proxy-revalidate," + + " s-maxage=5, stale-if-error=6, stale-while-revalidate=7"); } @Test public void invalidCacheControlCombination() { - CacheControlProperties cacheControl = new CacheControlProperties(); - cacheControl.setMaxAge(Duration.ofSeconds(4)); - cacheControl.setNoStore(true); - this.properties.setCacheControl(cacheControl); - assertThat(this.properties.getCacheControl().toHttpCacheControl().getHeaderValue()).isEqualTo("no-store"); - } - - @Test - public void cacheControlNoPropertiesSet() { - this.properties.setCacheControl(new CacheControlProperties()); - assertThat(this.properties.getCacheControl().toHttpCacheControl().getHeaderValue()).isNull(); + CacheControlProperties cacheControlProperties = new CacheControlProperties(); + cacheControlProperties.setMaxAge(Duration.ofSeconds(4)); + cacheControlProperties.setNoStore(true); + this.properties.setCacheControl(cacheControlProperties); + CacheControl cacheControl = this.properties.getCacheControl() + .toHttpCacheControl(); + assertThat(cacheControl.getHeaderValue()).isEqualTo("no-store"); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java index 1fa2f49841b..6d0537f9373 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java @@ -810,15 +810,15 @@ public class WebMvcAutoConfigurationTests { } private void assertCachePeriod(AssertableWebApplicationContext context) { - Map handlerMap = getHandlerMap(context - .getBean("resourceHandlerMapping", HandlerMapping.class)); + Map handlerMap = getHandlerMap( + context.getBean("resourceHandlerMapping", HandlerMapping.class)); assertThat(handlerMap).hasSize(2); for (Object handler : handlerMap.keySet()) { if (handler instanceof ResourceHttpRequestHandler) { - assertThat(((ResourceHttpRequestHandler) handler) - .getCacheSeconds()).isEqualTo(-1); - assertThat(((ResourceHttpRequestHandler) handler) - .getCacheControl()).isEqualToComparingFieldByField( + assertThat(((ResourceHttpRequestHandler) handler).getCacheSeconds()) + .isEqualTo(-1); + assertThat(((ResourceHttpRequestHandler) handler).getCacheControl()) + .isEqualToComparingFieldByField( CacheControl.maxAge(5, TimeUnit.SECONDS)); } } @@ -835,17 +835,16 @@ public class WebMvcAutoConfigurationTests { } private void assertCacheControl(AssertableWebApplicationContext context) { - Map handlerMap = getHandlerMap(context - .getBean("resourceHandlerMapping", HandlerMapping.class)); + Map handlerMap = getHandlerMap( + context.getBean("resourceHandlerMapping", HandlerMapping.class)); assertThat(handlerMap).hasSize(2); for (Object handler : handlerMap.keySet()) { if (handler instanceof ResourceHttpRequestHandler) { - assertThat(((ResourceHttpRequestHandler) handler) - .getCacheSeconds()).isEqualTo(-1); - assertThat(((ResourceHttpRequestHandler) handler) - .getCacheControl()).isEqualToComparingFieldByField( - CacheControl.maxAge(5, TimeUnit.SECONDS) - .proxyRevalidate()); + assertThat(((ResourceHttpRequestHandler) handler).getCacheSeconds()) + .isEqualTo(-1); + assertThat(((ResourceHttpRequestHandler) handler).getCacheControl()) + .isEqualToComparingFieldByField(CacheControl + .maxAge(5, TimeUnit.SECONDS).proxyRevalidate()); } } } @@ -896,7 +895,6 @@ public class WebMvcAutoConfigurationTests { return Collections.emptyMap(); } - @Configuration protected static class ViewConfig {