FreemarkerServlet ResponseCharacterEncoding init-param doesn't use the "force" prefix anymore, you just specify the charset name as its value.
Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/7540a51c Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/7540a51c Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/7540a51c Branch: refs/heads/2.3-gae Commit: 7540a51c13e9b666bea6e8e5065cb1ee1712aee8 Parents: 947428a Author: ddekany <[email protected]> Authored: Thu Nov 26 22:36:42 2015 +0100 Committer: ddekany <[email protected]> Committed: Thu Nov 26 23:44:19 2015 +0100 ---------------------------------------------------------------------- .../ext/servlet/FreemarkerServlet.java | 81 +++++++++++++------- src/manual/book.xml | 32 ++++++-- .../ext/servlet/FreemarkerServletTest.java | 12 +-- 3 files changed, 85 insertions(+), 40 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7540a51c/src/main/java/freemarker/ext/servlet/FreemarkerServlet.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/ext/servlet/FreemarkerServlet.java b/src/main/java/freemarker/ext/servlet/FreemarkerServlet.java index d745010..092dc8e 100644 --- a/src/main/java/freemarker/ext/servlet/FreemarkerServlet.java +++ b/src/main/java/freemarker/ext/servlet/FreemarkerServlet.java @@ -21,6 +21,8 @@ package freemarker.ext.servlet; import java.io.IOException; import java.nio.charset.Charset; +import java.nio.charset.IllegalCharsetNameException; +import java.nio.charset.UnsupportedCharsetException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -45,6 +47,7 @@ import freemarker.cache.FileTemplateLoader; import freemarker.cache.MultiTemplateLoader; import freemarker.cache.TemplateLoader; import freemarker.cache.WebappTemplateLoader; +import freemarker.core.BugException; import freemarker.core.Configurable; import freemarker.core.Environment; import freemarker.core.OutputFormat; @@ -162,8 +165,7 @@ import freemarker.template.utility.StringUtil; * the default of it), the content type may include the charset (as in <tt>"text/html; charset=utf-8"</tt>), in which * case that specifies the actual charset of the output. If the the {@value #INIT_PARAM_RESPONSE_CHARACTER_ENCODING} * init-param is not set to {@value #INIT_PARAM_VALUE_LEGACY}, then specifying the charset in the - * {@value #INIT_PARAM_CONTENT_TYPE} init-param is not allowed, and will cause servlet initialization error. - * </li> + * {@value #INIT_PARAM_CONTENT_TYPE} init-param is not allowed, and will cause servlet initialization error.</li> * * <li><strong>{@value #INIT_PARAM_OVERRIDE_RESPONSE_CONTENT_TYPE}</strong> (since 2.3.24): Specifies when we should * override the {@code contentType} that might be already set (i.e., non-{@code null}) in the @@ -185,7 +187,7 @@ import freemarker.template.utility.StringUtil; * * <li><strong>{@value #INIT_PARAM_RESPONSE_CHARACTER_ENCODING}</strong> (since 2.3.24): Specifies how the * {@link HttpServletResponse} "character encoding" (as in {@link HttpServletResponse#setCharacterEncoding(String)}) - * will deduced. The possible modes are: + * will be deduced. The possible modes are: * <ul> * <li>{@value #INIT_PARAM_VALUE_LEGACY}: This is the default for backward compatibility; in new applications, use * {@value #INIT_PARAM_VALUE_FROM_TEMPLATE} (or some of the other options) instead. {@value #INIT_PARAM_VALUE_LEGACY} @@ -195,8 +197,8 @@ import freemarker.template.utility.StringUtil; * or writes it (though very few applications utilize that setting anyway). Also, it sets the charset of the servlet * response by adding it to the response content type via calling {@link HttpServletResponse#setContentType(String)} (as * that was the only way before Servlet 2.4), not via the more modern - * {@link HttpServletResponse#setCharacterEncoding(String)} method. Note that the charset of a template usually - * comes from {@link Configuration#getDefaultEncoding()} (i.e., from the {@code default_encoding} FreeMarker setting), + * {@link HttpServletResponse#setCharacterEncoding(String)} method. Note that the charset of a template usually comes + * from {@link Configuration#getDefaultEncoding()} (i.e., from the {@code default_encoding} FreeMarker setting), * occasionally from {@link Configuration#getEncoding(Locale)} (when FreeMarker was configured to use different charsets * depending on the locale) or even more rarely from {@link Configuration#getTemplateConfigurers()} (when FreeMarker was * configured to use a specific charset for certain templates). @@ -205,16 +207,16 @@ import freemarker.template.utility.StringUtil; * template usually just inherits that from the {@link Configuration}), and if that's not set, then reads the source * charset of the template, just like {@value #INIT_PARAM_VALUE_LEGACY}. Then it passes the charset acquired this way to * {@link HttpServletResponse#setCharacterEncoding(String)} and {@link Environment#setOutputEncoding(String)}. (It - * doesn't call the legacy {@link HttpServletResponse#setContentType(String)} API to set the charset.) (Note that if - * the template has a {@code content_type} template attribute (which is deprecated) that specifies a charset, it will be - * considered as the output charset of that template.) + * doesn't call the legacy {@link HttpServletResponse#setContentType(String)} API to set the charset.) (Note that if the + * template has a {@code content_type} template attribute (which is deprecated) that specifies a charset, it will be + * used as the output charset of that template.) * <li>{@value #INIT_PARAM_VALUE_DO_NOT_SET}: {@link FreemarkerServlet} will not set the {@link HttpServletResponse} * "character encoding". It will still call {@link Environment#setOutputEncoding(String)}, so that the running template * will be aware of the charset used for the output. - * <li>{@value #INIT_PARAM_VALUE_FORCE_PREFIX} + charset name, for example {@code force UTF-8}: The output charset will - * be the one specified after "force" + space, regardless of everything. The charset specified this way is passed to - * {@link HttpServletResponse#setCharacterEncoding(String)} and {@link Environment#setOutputEncoding(String)}. If the - * charset name is not recognized by Java, the servlet initialization will fail. + * <li>A charset name, for example {@code UTF-8}: The output charset will the specified charset, regardless of + * everything. The charset specified this way is passed to {@link HttpServletResponse#setCharacterEncoding(String)} and + * {@link Environment#setOutputEncoding(String)}. If the charset name is not recognized by Java, the servlet + * initialization will fail. * </ul> * * <li><strong>{@value #INIT_PARAM_BUFFER_SIZE}</strong>: Sets the size of the output buffer in bytes, or if "KB" or @@ -417,7 +419,6 @@ public class FreemarkerServlet extends HttpServlet { public static final String INIT_PARAM_VALUE_FROM_TEMPLATE = "fromTemplate"; public static final String INIT_PARAM_VALUE_LEGACY = "legacy"; public static final String INIT_PARAM_VALUE_DO_NOT_SET = "doNotSet"; - public static final String INIT_PARAM_VALUE_FORCE_PREFIX = "force "; /** * When set, the items defined in it will be added after those coming from the @@ -668,9 +669,20 @@ public class FreemarkerServlet extends HttpServlet { overrideResponseContentType = initParamValueToEnum(value, OverrideResponseContentType.values()); } else if (name.equals(INIT_PARAM_RESPONSE_CHARACTER_ENCODING)) { responseCharacterEncoding = initParamValueToEnum(value, ResponseCharacterEncoding.values()); - if (responseCharacterEncoding == ResponseCharacterEncoding.FORCE_CHARSET) { - String charsetName = value.substring(INIT_PARAM_VALUE_FORCE_PREFIX.length()).trim(); - forcedResponseCharacterEncoding = Charset.forName(charsetName); + if (responseCharacterEncoding == ResponseCharacterEncoding.SPECIFIC_CHARSET) { + try { + forcedResponseCharacterEncoding = Charset.forName(value); + } catch (IllegalArgumentException e) { + if (!(e instanceof UnsupportedCharsetException + || e instanceof IllegalCharsetNameException)) { + throw e; + } + StringBuilder sb = new StringBuilder(); + sb.append(StringUtil.jQuote(value)); + sb.append(" isn't a valid charset name, nor it is any of the predefined values: "); + appendEnumInitParamValues(sb, ResponseCharacterEncoding.values()); + throw new IllegalArgumentException(sb.toString()); + } } } else if (name.equals(INIT_PARAM_OVERRIDE_RESPONSE_LOCALE)) { overrideResponseLocale = initParamValueToEnum(value, OverrideResponseLocale.values()); @@ -846,7 +858,7 @@ public class FreemarkerServlet extends HttpServlet { if (responseCharacterEncoding != ResponseCharacterEncoding.LEGACY && responseCharacterEncoding != ResponseCharacterEncoding.DO_NOT_SET) { // Using the Servlet 2.4 way of setting character encoding. - if (responseCharacterEncoding != ResponseCharacterEncoding.FORCE_CHARSET) { + if (responseCharacterEncoding != ResponseCharacterEncoding.SPECIFIC_CHARSET) { if (!tempSpecContentTypeContainsCharset) { response.setCharacterEncoding(getTemplateSpecificOutputEncoding(template)); } @@ -1589,28 +1601,42 @@ public class FreemarkerServlet extends HttpServlet { } private <T extends InitParamValueEnum> T initParamValueToEnum(String initParamValue, T[] enumValues) { + T wildcardEnumValue = null; for (T enumValue : enumValues) { String enumInitParamValue = enumValue.getInitParamValue(); - if (initParamValue.equals(enumInitParamValue) - || enumInitParamValue.endsWith("}") && initParamValue.startsWith( - enumInitParamValue.substring(0, enumInitParamValue.indexOf("${")))) { + if (enumInitParamValue == null) { + if (wildcardEnumValue != null) { + throw new BugException(); + } + wildcardEnumValue = enumValue; + } else if (initParamValue.equals(enumInitParamValue)) { return enumValue; } } + if (wildcardEnumValue != null) { + return wildcardEnumValue; + } StringBuilder sb = new StringBuilder(); sb.append(StringUtil.jQuote(initParamValue)); sb.append(" is not a one of the enumeration values: "); + appendEnumInitParamValues(sb, enumValues); + throw new IllegalArgumentException(sb.toString()); + } + + protected <T extends InitParamValueEnum> void appendEnumInitParamValues(StringBuilder sb, T[] enumValues) { boolean first = true; for (T value : enumValues) { - if (!first) { - sb.append(", "); - } else { - first = false; + String initParamValue = value.getInitParamValue(); + if (initParamValue != null) { // Not a wildcard enum + if (!first) { + sb.append(", "); + } else { + first = false; + } + sb.append(StringUtil.jQuote(initParamValue)); } - sb.append(StringUtil.jQuote(value.getInitParamValue())); } - throw new IllegalArgumentException(sb.toString()); } /** @@ -1643,7 +1669,7 @@ public class FreemarkerServlet extends HttpServlet { LEGACY(INIT_PARAM_VALUE_LEGACY), FROM_TEMPLATE(INIT_PARAM_VALUE_FROM_TEMPLATE), DO_NOT_SET(INIT_PARAM_VALUE_DO_NOT_SET), - FORCE_CHARSET(INIT_PARAM_VALUE_FORCE_PREFIX + "${charsetName}"); + SPECIFIC_CHARSET(null); private final String initParamValue; @@ -1655,7 +1681,6 @@ public class FreemarkerServlet extends HttpServlet { public String getInitParamValue() { return initParamValue; } - } private enum OverrideResponseLocale implements InitParamValueEnum { http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7540a51c/src/manual/book.xml ---------------------------------------------------------------------- diff --git a/src/manual/book.xml b/src/manual/book.xml index c6f8033..1654417 100644 --- a/src/manual/book.xml +++ b/src/manual/book.xml @@ -10427,7 +10427,11 @@ TemplateHashModel roundingModeEnums = </init-param> <init-param> <param-name>ContentType</param-name> - <param-value>text/html; charset=UTF-8</param-value> <!-- Forces UTF-8 output encoding! --> + <param-value>text/html</param-value> + </init-param> + <init-param> + <param-name>ResponseCharacterEncoding</param-name> + <param-value>UTF-8</param-value> </init-param> <!-- FreeMarker settings: --> @@ -26080,9 +26084,8 @@ TemplateModel x = env.getVariable("x"); // get variable x</programlisting> the <literal>outputEncoding</literal> setting), <literal>doNotSet</literal> (keeps what the caller has already set in the <literal>ServletRespone</literal>) and - <literal>force - <replaceable>charsetName</replaceable></literal> (forces a - specific charset).</para> + any valid charset name (forces a specific output + charset).</para> </listitem> </itemizedlist> </listitem> @@ -26420,7 +26423,7 @@ TemplateModel x = env.getVariable("x"); // get variable x</programlisting> <itemizedlist> <listitem> - <para><literal>OverrideResponseContentType</literal>. + <para><literal>OverrideResponseContentType</literal>: Specifies when should we override the <literal>contentType</literal> that's already set (i.e., non-<literal>null</literal>) in the @@ -26433,13 +26436,30 @@ TemplateModel x = env.getVariable("x"); // get variable x</programlisting> </listitem> <listitem> - <para><literal>OverrideResponseLocale</literal>. Specifies + <para><literal>OverrideResponseLocale</literal>: Specifies if should we override the <literal>contentType</literal> that's already set (i.e., non-<literal>null</literal>) in the <literal>HttpServletResponse</literal>. Earlier, we have always set it, but now this behavior can be changed so that we only set it if it wasn't already set.</para> </listitem> + + <listitem> + <para><literal>ResponseCharacterEncoding</literal>: + Deprecates the old (and quirky) logic of specifying the + output charset, which was putting it into the + <literal>ContentType</literal> init-param after the MIME + type, otherwise falling back to using the template file + charset. The possible values are <literal>legacy</literal> + (the default for backward compatibility), + <literal>fromTemplate</literal> (which is + <literal>legacy</literal> without quirks, and is aware of + the <literal>outputEncoding</literal> setting), + <literal>doNotSet</literal> (keeps what the caller has + already set in the <literal>ServletRespone</literal>) and + any valid charset name (forces a specific output + charset).</para> + </listitem> </itemizedlist> </listitem> http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7540a51c/src/test/java/freemarker/ext/servlet/FreemarkerServletTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/freemarker/ext/servlet/FreemarkerServletTest.java b/src/test/java/freemarker/ext/servlet/FreemarkerServletTest.java index f008280..6e5ce09 100644 --- a/src/test/java/freemarker/ext/servlet/FreemarkerServletTest.java +++ b/src/test/java/freemarker/ext/servlet/FreemarkerServletTest.java @@ -310,23 +310,23 @@ public class FreemarkerServletTest { assertOutputEncodingEquals( "UTF-16LE", // <- expected response.characterEncoding "UTF-16LE", // <- expected env.outputEncoding - FreemarkerServlet.INIT_PARAM_VALUE_FORCE_PREFIX + "UTF-16LE", // <- init-param + "UTF-16LE", // <- init-param FOO_FTL); assertOutputEncodingEquals( "UTF-16LE", // <- expected response.characterEncoding "UTF-16LE", // <- expected env.outputEncoding - FreemarkerServlet.INIT_PARAM_VALUE_FORCE_PREFIX + "UTF-16LE", // <- init-param + "UTF-16LE", // <- init-param FOO_SRC_UTF8_FTL); assertOutputEncodingEquals( "UTF-16LE", // <- expected response.characterEncoding "UTF-16LE", // <- expected env.outputEncoding - FreemarkerServlet.INIT_PARAM_VALUE_FORCE_PREFIX + "UTF-16LE", // <- init-param + "UTF-16LE", // <- init-param FOO_OUT_UTF8_FTL); try { assertOutputEncodingEquals( null, // <- expected response.characterEncoding null, // <- expected env.outputEncoding - FreemarkerServlet.INIT_PARAM_VALUE_FORCE_PREFIX + "noSuchCharset", // <- init-param + "noSuchCharset", // <- init-param FOO_FTL); fail(); } catch (ServletException e) { @@ -337,7 +337,7 @@ public class FreemarkerServletTest { assertOutputEncodingEquals( "UTF-16LE", // <- expected response.characterEncoding "UTF-16LE", // <- expected env.outputEncoding - FreemarkerServlet.INIT_PARAM_VALUE_FORCE_PREFIX + "UTF-16LE", // <- init-param + "UTF-16LE", // <- init-param "text/html; charset=ISO-8859-2", // ContentType init-param FOO_FTL); fail(); @@ -348,7 +348,7 @@ public class FreemarkerServletTest { assertOutputEncodingEquals( "UTF-16LE", // <- expected response.characterEncoding "UTF-16LE", // <- expected env.outputEncoding - FreemarkerServlet.INIT_PARAM_VALUE_FORCE_PREFIX + "UTF-16LE", // <- init-param + "UTF-16LE", // <- init-param CONTENT_TYPE_ATTR_WITH_CHARSET_FTL); }
