Set output_encoding in FreeMarkerView implementations

According to the official FreeMarker documentation, Spring's
FreeMarkerView implementations should be configuring the
output_encoding for template rendering.

To address that, this commit modifies the FreeMarkerView
implementations in Web MVC and WebFlux to explicitly set the
output_encoding for template rendering.

See https://freemarker.apache.org/docs/pgui_misc_charset.html#autoid_53
See gh-33071
Closes gh-33106
This commit is contained in:
Sam Brannen
2024-06-27 10:03:26 +02:00
parent 95887c81b9
commit 8b95697c8d
7 changed files with 71 additions and 27 deletions

View File

@@ -26,6 +26,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import freemarker.core.Environment;
import freemarker.core.ParseException;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapperBuilder;
@@ -333,7 +334,9 @@ public class FreeMarkerView extends AbstractUrlBasedView {
FastByteArrayOutputStream bos = new FastByteArrayOutputStream();
Charset charset = getCharset(contentType);
Writer writer = new OutputStreamWriter(bos, charset);
template.process(freeMarkerModel, writer);
Environment env = template.createProcessingEnvironment(freeMarkerModel, writer);
env.setOutputEncoding(charset.name());
env.process();
byte[] bytes = bos.toByteArrayUnsafe();
DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);
return Mono.just(buffer);

View File

@@ -58,12 +58,20 @@ class WebFluxViewResolutionIntegrationTests {
private static final MediaType TEXT_HTML_ISO_8859_1 = MediaType.parseMediaType("text/html;charset=ISO-8859-1");
private static final String EXPECTED_BODY = "<html><body>Hello, Java Café</body></html>";
@Nested
class FreeMarkerTests {
private static final String EXPECTED_BODY = """
<html>
<body>
<h1>Hello, Java Café</h1>
<p>output_encoding: %s</p>
</body>
</html>
""";
private static final ClassTemplateLoader classTemplateLoader =
new ClassTemplateLoader(WebFluxViewResolutionIntegrationTests.class, "");
@@ -77,21 +85,21 @@ class WebFluxViewResolutionIntegrationTests {
@Test
void freemarkerWithDefaults() throws Exception {
MockServerHttpResponse response = runTest(FreeMarkerWebFluxConfig.class);
StepVerifier.create(response.getBodyAsString()).expectNext(EXPECTED_BODY).expectComplete().verify();
StepVerifier.create(response.getBodyAsString()).expectNext(EXPECTED_BODY.formatted("UTF-8")).expectComplete().verify();
assertThat(response.getHeaders().getContentType()).isEqualTo(TEXT_HTML_UTF8);
}
@Test
void freemarkerWithExplicitDefaultEncoding() throws Exception {
MockServerHttpResponse response = runTest(ExplicitDefaultEncodingConfig.class);
StepVerifier.create(response.getBodyAsString()).expectNext(EXPECTED_BODY).expectComplete().verify();
StepVerifier.create(response.getBodyAsString()).expectNext(EXPECTED_BODY.formatted("UTF-8")).expectComplete().verify();
assertThat(response.getHeaders().getContentType()).isEqualTo(TEXT_HTML_UTF8);
}
@Test
void freemarkerWithExplicitDefaultEncodingAndContentType() throws Exception {
MockServerHttpResponse response = runTest(ExplicitDefaultEncodingAndContentTypeConfig.class);
StepVerifier.create(response.getBodyAsString()).expectNext(EXPECTED_BODY).expectComplete().verify();
StepVerifier.create(response.getBodyAsString()).expectNext(EXPECTED_BODY.formatted("ISO-8859-1")).expectComplete().verify();
// When the Content-Type (supported media type) is explicitly set on the view resolver, it should be used.
assertThat(response.getHeaders().getContentType()).isEqualTo(TEXT_HTML_ISO_8859_1);
}

View File

@@ -1 +1,6 @@
<html><body>${hello}, Java Caf<61></body></html>
<html>
<body>
<h1>${hello}, Java Caf<61></h1>
<p>output_encoding: ${.output_encoding}</p>
</body>
</html>

View File

@@ -1 +1,6 @@
<html><body>${hello}, Java Café</body></html>
<html>
<body>
<h1>${hello}, Java Café</h1>
<p>output_encoding: ${.output_encoding}</p>
</body>
</html>