diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mustache/MustacheProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mustache/MustacheProperties.java index dd16e42f57..210ecd575b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mustache/MustacheProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mustache/MustacheProperties.java @@ -18,9 +18,11 @@ package org.springframework.boot.autoconfigure.mustache; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.util.List; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.DeprecatedConfigurationProperty; +import org.springframework.http.MediaType; import org.springframework.util.MimeType; /** @@ -42,6 +44,8 @@ public class MustacheProperties { private final Servlet servlet = new Servlet(); + private final Reactive reactive = new Reactive(); + /** * View names that can be resolved. */ @@ -81,6 +85,10 @@ public class MustacheProperties { return this.servlet; } + public Reactive getReactive() { + return this.reactive; + } + public String getPrefix() { return this.prefix; } @@ -318,4 +326,21 @@ public class MustacheProperties { } + public static class Reactive { + + /** + * Media types supported by Mustache views. + */ + private List mediaTypes; + + public List getMediaTypes() { + return this.mediaTypes; + } + + public void setMediaTypes(List mediaTypes) { + this.mediaTypes = mediaTypes; + } + + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mustache/MustacheReactiveWebConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mustache/MustacheReactiveWebConfiguration.java index 729fb82b55..eb27d95788 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mustache/MustacheReactiveWebConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mustache/MustacheReactiveWebConfiguration.java @@ -22,6 +22,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; +import org.springframework.boot.context.properties.PropertyMapper; import org.springframework.boot.web.reactive.result.view.MustacheViewResolver; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -36,11 +37,13 @@ class MustacheReactiveWebConfiguration { @ConditionalOnProperty(prefix = "spring.mustache", name = "enabled", matchIfMissing = true) MustacheViewResolver mustacheViewResolver(Compiler mustacheCompiler, MustacheProperties mustache) { MustacheViewResolver resolver = new MustacheViewResolver(mustacheCompiler); - resolver.setPrefix(mustache.getPrefix()); - resolver.setSuffix(mustache.getSuffix()); - resolver.setViewNames(mustache.getViewNames()); - resolver.setRequestContextAttribute(mustache.getRequestContextAttribute()); - resolver.setCharset(mustache.getCharsetName()); + PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); + map.from(mustache::getPrefix).to(resolver::setPrefix); + map.from(mustache::getSuffix).to(resolver::setSuffix); + map.from(mustache::getViewNames).to(resolver::setViewNames); + map.from(mustache::getRequestContextAttribute).to(resolver::setRequestContextAttribute); + map.from(mustache::getCharsetName).to(resolver::setCharset); + map.from(mustache.getReactive()::getMediaTypes).to(resolver::setSupportedMediaTypes); resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10); return resolver; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 7b0e225779..c6583d470c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1627,6 +1627,10 @@ "name": "spring.mustache.prefix", "defaultValue": "classpath:/templates/" }, + { + "name": "spring.mustache.reactive.media-types", + "defaultValue": "text/html;charset=UTF-8" + }, { "name": "spring.mustache.suffix", "defaultValue": ".mustache" diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mustache/MustacheAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mustache/MustacheAutoConfigurationTests.java index 48817dda71..185c20b35b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mustache/MustacheAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mustache/MustacheAutoConfigurationTests.java @@ -16,6 +16,7 @@ package org.springframework.boot.autoconfigure.mustache; +import java.util.Arrays; import java.util.function.Supplier; import com.samskivert.mustache.Mustache; @@ -31,6 +32,7 @@ import org.springframework.boot.test.context.runner.WebApplicationContextRunner; import org.springframework.boot.web.servlet.view.MustacheViewResolver; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; import static org.assertj.core.api.Assertions.assertThat; @@ -133,6 +135,8 @@ class MustacheAutoConfigurationTests { assertThat(viewResolver).extracting("prefix").isEqualTo("classpath:/templates/"); assertThat(viewResolver).extracting("requestContextAttribute").isNull(); assertThat(viewResolver).extracting("suffix").isEqualTo(".mustache"); + assertThat(viewResolver.getSupportedMediaTypes()) + .containsExactly(MediaType.parseMediaType("text/html;charset=UTF-8")); }); } @@ -238,6 +242,14 @@ class MustacheAutoConfigurationTests { assertViewResolverProperty(kind, "spring.mustache.suffix=.tache", "suffix", ".tache"); } + @Test + void mediaTypesCanBeCustomizedOnReactiveViewResolver() { + assertViewResolverProperty(ViewResolverKind.REACTIVE, + "spring.mustache.reactive.media-types=text/xml;charset=UTF-8,text/plain;charset=UTF-16", "mediaTypes", + Arrays.asList(MediaType.parseMediaType("text/xml;charset=UTF-8"), + MediaType.parseMediaType("text/plain;charset=UTF-16"))); + } + private void assertViewResolverProperty(ViewResolverKind kind, String property, String field, Object expectedValue) { kind.runner().withConfiguration(AutoConfigurations.of(MustacheAutoConfiguration.class))