This commit is contained in:
Phillip Webb 2017-11-29 08:58:19 -08:00
parent 159a758e19
commit d7251f52a4
13 changed files with 114 additions and 66 deletions

View File

@ -20,6 +20,11 @@ import java.util.Properties;
import org.springframework.ui.freemarker.FreeMarkerConfigurationFactory;
/**
* Base class for shared FreeMarker configuration.
*
* @author Brian Clozel
*/
class AbstractFreeMarkerConfiguration {
private final FreeMarkerProperties properties;
@ -28,7 +33,7 @@ class AbstractFreeMarkerConfiguration {
this.properties = properties;
}
protected FreeMarkerProperties getProperties() {
protected final FreeMarkerProperties getProperties() {
return this.properties;
}
@ -40,4 +45,5 @@ class AbstractFreeMarkerConfiguration {
settings.putAll(this.properties.getSettings());
factory.setFreemarkerSettings(settings);
}
}

View File

@ -26,16 +26,12 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication;
import org.springframework.boot.autoconfigure.template.TemplateLocation;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.ui.freemarker.FreeMarkerConfigurationFactory;
import org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean;
/**
* {@link EnableAutoConfiguration Auto-configuration} for FreeMarker.
@ -46,10 +42,11 @@ import org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean;
* @since 1.1.0
*/
@Configuration
@ConditionalOnClass({freemarker.template.Configuration.class,
FreeMarkerConfigurationFactory.class})
@ConditionalOnClass({ freemarker.template.Configuration.class,
FreeMarkerConfigurationFactory.class })
@EnableConfigurationProperties(FreeMarkerProperties.class)
@Import({FreeMarkerServletWebConfiguration.class, FreeMarkerReactiveWebConfiguration.class})
@Import({ FreeMarkerServletWebConfiguration.class,
FreeMarkerReactiveWebConfiguration.class, FreeMarkerNonWebConfiguration.class })
public class FreeMarkerAutoConfiguration {
private static final Log logger = LogFactory
@ -87,22 +84,4 @@ public class FreeMarkerAutoConfiguration {
}
}
@Configuration
@ConditionalOnNotWebApplication
public static class FreeMarkerNonWebConfiguration extends AbstractFreeMarkerConfiguration {
public FreeMarkerNonWebConfiguration(FreeMarkerProperties properties) {
super(properties);
}
@Bean
@ConditionalOnMissingBean
public FreeMarkerConfigurationFactoryBean freeMarkerConfiguration() {
FreeMarkerConfigurationFactoryBean freeMarkerFactoryBean = new FreeMarkerConfigurationFactoryBean();
applyProperties(freeMarkerFactoryBean);
return freeMarkerFactoryBean;
}
}
}

View File

@ -0,0 +1,47 @@
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.freemarker;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean;
/**
* Configuration for FreeMarker when used in a non-web context.
*
* @author Brian Clozel
* @author Andy Wilkinson
*/
@Configuration
@ConditionalOnNotWebApplication
public class FreeMarkerNonWebConfiguration extends AbstractFreeMarkerConfiguration {
public FreeMarkerNonWebConfiguration(FreeMarkerProperties properties) {
super(properties);
}
@Bean
@ConditionalOnMissingBean
public FreeMarkerConfigurationFactoryBean freeMarkerConfiguration() {
FreeMarkerConfigurationFactoryBean freeMarkerFactoryBean = new FreeMarkerConfigurationFactoryBean();
applyProperties(freeMarkerFactoryBean);
return freeMarkerFactoryBean;
}
}

View File

@ -27,6 +27,12 @@ import org.springframework.web.reactive.result.view.freemarker.FreeMarkerConfig;
import org.springframework.web.reactive.result.view.freemarker.FreeMarkerConfigurer;
import org.springframework.web.reactive.result.view.freemarker.FreeMarkerViewResolver;
/**
* Configuration for FreeMarker when used in a reactive web context.
*
* @author Brian Clozel
* @author Andy Wilkinson
*/
@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@AutoConfigureAfter(WebFluxAutoConfiguration.class)

View File

@ -32,9 +32,15 @@ import org.springframework.web.servlet.view.freemarker.FreeMarkerConfig;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;
/**
* Configuration for FreeMarker when used in a servlet web context.
*
* @author Brian Clozel
* @author Andy Wilkinson
*/
@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass({Servlet.class, FreeMarkerConfigurer.class})
@ConditionalOnClass({ Servlet.class, FreeMarkerConfigurer.class })
@AutoConfigureAfter(WebMvcAutoConfiguration.class)
class FreeMarkerServletWebConfiguration extends AbstractFreeMarkerConfiguration {

View File

@ -462,9 +462,12 @@ public class ResourceProperties {
org.springframework.http.CacheControl cacheControl = createCacheControl();
callIfTrue(this.mustRevalidate, cacheControl,
org.springframework.http.CacheControl::mustRevalidate);
callIfTrue(this.noTransform, cacheControl, org.springframework.http.CacheControl::noTransform);
callIfTrue(this.cachePublic, cacheControl, org.springframework.http.CacheControl::cachePublic);
callIfTrue(this.cachePrivate, cacheControl, org.springframework.http.CacheControl::cachePrivate);
callIfTrue(this.noTransform, cacheControl,
org.springframework.http.CacheControl::noTransform);
callIfTrue(this.cachePublic, cacheControl,
org.springframework.http.CacheControl::cachePublic);
callIfTrue(this.cachePrivate, cacheControl,
org.springframework.http.CacheControl::cachePrivate);
callIfTrue(this.proxyRevalidate, cacheControl,
org.springframework.http.CacheControl::proxyRevalidate);
if (this.staleWhileRevalidate != null) {
@ -489,8 +492,8 @@ public class ResourceProperties {
return org.springframework.http.CacheControl.noCache();
}
if (this.maxAge != null) {
return org.springframework.http.CacheControl.maxAge(this.maxAge.getSeconds(),
TimeUnit.SECONDS);
return org.springframework.http.CacheControl
.maxAge(this.maxAge.getSeconds(), TimeUnit.SECONDS);
}
return org.springframework.http.CacheControl.empty();
}

View File

@ -220,17 +220,15 @@ public abstract class AbstractErrorWebExceptionHandler
@Override
public Mono<Void> handle(ServerWebExchange exchange, Throwable throwable) {
if (!exchange.getResponse().isCommitted()) {
this.errorAttributes.storeErrorInformation(throwable, exchange);
ServerRequest request = ServerRequest.create(exchange, this.messageReaders);
return getRoutingFunction(this.errorAttributes).route(request)
.switchIfEmpty(Mono.error(throwable))
.flatMap((handler) -> handler.handle(request))
.flatMap((response) -> write(exchange, response));
}
else {
if (exchange.getResponse().isCommitted()) {
return Mono.error(throwable);
}
this.errorAttributes.storeErrorInformation(throwable, exchange);
ServerRequest request = ServerRequest.create(exchange, this.messageReaders);
return getRoutingFunction(this.errorAttributes).route(request)
.switchIfEmpty(Mono.error(throwable))
.flatMap((handler) -> handler.handle(request))
.flatMap((response) -> write(exchange, response));
}
private Mono<? extends Void> write(ServerWebExchange exchange,

View File

@ -44,7 +44,6 @@ public class FreeMarkerAutoConfigurationReactiveIntegrationTests {
private AnnotationConfigReactiveWebApplicationContext context = new AnnotationConfigReactiveWebApplicationContext();
@After
public void close() {
if (this.context != null) {
@ -58,7 +57,8 @@ public class FreeMarkerAutoConfigurationReactiveIntegrationTests {
assertThat(this.context.getBean(FreeMarkerViewResolver.class)).isNotNull();
assertThat(this.context.getBean(FreeMarkerConfigurer.class)).isNotNull();
assertThat(this.context.getBean(FreeMarkerConfig.class)).isNotNull();
assertThat(this.context.getBean(freemarker.template.Configuration.class)).isNotNull();
assertThat(this.context.getBean(freemarker.template.Configuration.class))
.isNotNull();
}
@Test
@ -67,7 +67,8 @@ public class FreeMarkerAutoConfigurationReactiveIntegrationTests {
MockServerWebExchange exchange = render("home");
String result = exchange.getResponse().getBodyAsString().block();
assertThat(result).contains("home");
assertThat(exchange.getResponse().getHeaders().getContentType()).isEqualTo(MediaType.TEXT_HTML);
assertThat(exchange.getResponse().getHeaders().getContentType())
.isEqualTo(MediaType.TEXT_HTML);
}
@Test
@ -132,4 +133,5 @@ public class FreeMarkerAutoConfigurationReactiveIntegrationTests {
view.flatMap(v -> v.render(null, MediaType.TEXT_HTML, exchange)).block();
return exchange;
}
}

View File

@ -69,7 +69,8 @@ public class FreeMarkerAutoConfigurationServletIntegrationTests {
assertThat(this.context.getBean(FreeMarkerViewResolver.class)).isNotNull();
assertThat(this.context.getBean(FreeMarkerConfigurer.class)).isNotNull();
assertThat(this.context.getBean(FreeMarkerConfig.class)).isNotNull();
assertThat(this.context.getBean(freemarker.template.Configuration.class)).isNotNull();
assertThat(this.context.getBean(freemarker.template.Configuration.class))
.isNotNull();
}
@Test

View File

@ -31,7 +31,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.containsString;
/**
* Tests for {@link FreeMarkerAutoConfiguration}
* Tests for {@link FreeMarkerAutoConfiguration}.
*
* @author Andy Wilkinson
* @author Kazuki Shimizu

View File

@ -73,8 +73,8 @@ public class ResourcePropertiesTests {
@Test
public void emptyCacheControl() {
org.springframework.http.CacheControl cacheControl = this.properties.getCache().getCachecontrol()
.toHttpCacheControl();
org.springframework.http.CacheControl cacheControl = this.properties.getCache()
.getCachecontrol().toHttpCacheControl();
assertThat(cacheControl.getHeaderValue()).isNull();
}
@ -90,7 +90,8 @@ public class ResourcePropertiesTests {
properties.setSMaxAge(Duration.ofSeconds(5));
properties.setStaleIfError(Duration.ofSeconds(6));
properties.setStaleWhileRevalidate(Duration.ofSeconds(7));
org.springframework.http.CacheControl cacheControl = properties.toHttpCacheControl();
org.springframework.http.CacheControl cacheControl = properties
.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");
@ -101,7 +102,8 @@ public class ResourcePropertiesTests {
Cache.Cachecontrol properties = this.properties.getCache().getCachecontrol();
properties.setMaxAge(Duration.ofSeconds(4));
properties.setNoStore(true);
org.springframework.http.CacheControl cacheControl = properties.toHttpCacheControl();
org.springframework.http.CacheControl cacheControl = properties
.toHttpCacheControl();
assertThat(cacheControl.getHeaderValue()).isEqualTo("no-store");
}

View File

@ -192,11 +192,12 @@ public class DefaultErrorWebExceptionHandlerIntegrationTest {
@Test
public void responseCommitted() throws Exception {
load();
this.webTestClient.get().uri("/commit").exchange()
.expectStatus().isEqualTo(HttpStatus.OK)
.expectBody().isEmpty();
this.output.expect(not(containsString("java.lang.UnsupportedOperationException")));
this.output.expect(containsString("java.lang.IllegalStateException: already committed!"));
this.webTestClient.get().uri("/commit").exchange().expectStatus()
.isEqualTo(HttpStatus.OK).expectBody().isEmpty();
this.output
.expect(not(containsString("java.lang.UnsupportedOperationException")));
this.output.expect(
containsString("java.lang.IllegalStateException: already committed!"));
}
private void load(String... arguments) {
@ -248,9 +249,8 @@ public class DefaultErrorWebExceptionHandlerIntegrationTest {
@GetMapping("/commit")
public Mono<Void> commit(ServerWebExchange exchange) {
return exchange
.getResponse().writeWith(Mono.empty())
.then(Mono.error(new IllegalStateException("already committed!")));
return exchange.getResponse().writeWith(Mono.empty()).then(
Mono.error(new IllegalStateException("already committed!")));
}
@PostMapping(path = "/bind", produces = "application/json")

View File

@ -73,18 +73,17 @@ public class NettyReactiveWebServerFactory extends AbstractReactiveWebServerFact
*/
public void setServerCustomizers(
Collection<? extends NettyServerCustomizer> serverCustomizers) {
Assert.notNull(serverCustomizers, "NettyServerCustomizers must not be null");
Assert.notNull(serverCustomizers, "ServerCustomizers must not be null");
this.serverCustomizers = new ArrayList<>(serverCustomizers);
}
/**
* Add {@link NettyServerCustomizer}s that should applied while building the server.
* @param nettyServerCustomizer the customizers to add
* @param serverCustomizers the customizers to add
*/
public void addServerCustomizers(NettyServerCustomizer... nettyServerCustomizer) {
Assert.notNull(nettyServerCustomizer,
"NettyWebServerCustomizer must not be null");
this.serverCustomizers.addAll(Arrays.asList(nettyServerCustomizer));
public void addServerCustomizers(NettyServerCustomizer... serverCustomizers) {
Assert.notNull(serverCustomizers, "ServerCustomizer must not be null");
this.serverCustomizers.addAll(Arrays.asList(serverCustomizers));
}
private HttpServer createHttpServer() {
@ -107,8 +106,7 @@ public class NettyReactiveWebServerFactory extends AbstractReactiveWebServerFact
}
private void applyCustomizers(Builder options) {
this.serverCustomizers
.forEach((customizer) -> customizer.customize(options));
this.serverCustomizers.forEach((customizer) -> customizer.customize(options));
}
}