Mostly CFormat-related code cleanup (things spotted during forward porting into FM3)
diff --git a/src/main/java/freemarker/core/ArithmeticEngine.java b/src/main/java/freemarker/core/ArithmeticEngine.java
index 468f5e4..dc946d2 100644
--- a/src/main/java/freemarker/core/ArithmeticEngine.java
+++ b/src/main/java/freemarker/core/ArithmeticEngine.java
@@ -116,7 +116,7 @@
@Override
public int compareNumbers(Number first, Number second) {
// We try to find the result based on the sign (+/-/0) first, because:
- // - It's much faster than converting to BigDecial, and comparing to 0 is the most common comparison.
+ // - It's much faster than converting to BigDecimal, and comparing to 0 is the most common comparison.
// - It doesn't require any type conversions, and thus things like "Infinity > 0" won't fail.
int firstSignum = NumberUtil.getSignum(first);
int secondSignum = NumberUtil.getSignum(second);
diff --git a/src/main/java/freemarker/core/CTemplateNumberFormat.java b/src/main/java/freemarker/core/CTemplateNumberFormat.java
index dc662b7..3df4177 100644
--- a/src/main/java/freemarker/core/CTemplateNumberFormat.java
+++ b/src/main/java/freemarker/core/CTemplateNumberFormat.java
@@ -136,11 +136,10 @@
BigDecimal bd = ((BigDecimal) num).stripTrailingZeros();
int scale = bd.scale();
if (scale <= 0) {
- // A whole number. Myabe a long ID in a database or other system, and for those exponential form is not
+ // A whole number. Maybe a long ID in a database or other system, and for those exponential form is not
// expected generally, so we avoid that. But then, it becomes too easy to write something like
// 1e1000000000000 and kill the server with a terra byte long rendering of the number, so for lengths
- // that
- // realistically aren't ID-s or such, we use exponential format after all:
+ // that realistically aren't ID-s or such, we use exponential format after all:
if (scale <= -100) {
return bd.toString(); // Will give exponential form for this scale
}
@@ -196,5 +195,4 @@
return "c";
}
-
}
diff --git a/src/main/java/freemarker/core/Configurable.java b/src/main/java/freemarker/core/Configurable.java
index 0e03b22..a70e247 100644
--- a/src/main/java/freemarker/core/Configurable.java
+++ b/src/main/java/freemarker/core/Configurable.java
@@ -66,6 +66,7 @@
import freemarker.template.Version;
import freemarker.template._TemplateAPI;
import freemarker.template._VersionInts;
+import freemarker.template.utility.CollectionUtils;
import freemarker.template.utility.NullArgumentException;
import freemarker.template.utility.StringUtil;
@@ -82,7 +83,7 @@
* object.
*/
public class Configurable {
- static final String C_TRUE_FALSE = "true,false";
+ static final String BOOLEAN_FORMAT_LEGACY_DEFAULT = "true,false";
static final String C_FORMAT_STRING = "c";
private static final String NULL = "null";
@@ -386,8 +387,6 @@
private TimeZone sqlDataAndTimeTimeZone;
private boolean sqlDataAndTimeTimeZoneSet;
private String booleanFormat;
- private String booleanFormatCommaSplitTrueSide; // deduced from booleanFormat
- private String booleanFormatCommaSplitFalseSide; // deduced from booleanFormat
private Integer classicCompatible;
private TemplateExceptionHandler templateExceptionHandler;
private AttemptExceptionReporter attemptExceptionReporter;
@@ -493,7 +492,7 @@
// outputEncoding and urlEscapingCharset defaults to null,
// which means "not specified"
- setBooleanFormat(C_TRUE_FALSE);
+ setBooleanFormat(BOOLEAN_FORMAT_LEGACY_DEFAULT);
customAttributes = new HashMap();
@@ -697,12 +696,13 @@
}
/**
- * Sets the format (usually a computer language) used for the {@code c}, {@code cn} built-ins, and for the
+ * Sets the format (usually a computer language) used for {@code ?c}, {@code ?cn}, and for the
* {@code "c"} ({@code "computer"} before 2.3.32) {@link #setNumberFormat(String) number_format}, and the
* {@code "c"} {@link #setBooleanFormat(String) boolean_format}.
*
* <p>The default value depends on {@link Configuration#Configuration(Version) incompatible_improvements}.
- * If that's 2.3.32 or higher, then it's {@code "JavaScript or JSON"}, otherwise it's {@code "legacy"}.
+ * If that's 2.3.32 or higher, then it's {@link JavaScriptOrJSONCFormat#INSTANCE "JavaScript or JSON"},
+ * otherwise it's {@link LegacyCFormat#INSTANCE "legacy"}.
*
* @since 2.3.32
*/
@@ -863,7 +863,7 @@
* <li>{@code "c"} (recognized since 2.3.32): The number format used by FTL's {@code c} built-in (like in
* {@code someNumber?c}). So with this <code>${someNumber}</code> will output the same as
* <code>${someNumber?c}</code>. This should only be used if the template solely generates source code,
- * configuration file, or other content that's nor read by normal users. If the template contains parts that's
+ * configuration file, or other content that's not read by normal users. If the template contains parts that's
* read by normal users (like typical a web page), you are not supposed to use this.</li>
* <li>{@code "computer"}: The old (deprecated) name for {@code "c"}. Recognized by all FreeMarker versions.</li>
* <li>{@code "currency"}: The number format returned by {@link NumberFormat#getCurrencyInstance(Locale)}</li>
@@ -882,8 +882,7 @@
* <code><i>parameters</i></code> is parsed by the custom {@link TemplateNumberFormat}.
* </li>
* </ul>
- *
- *
+ *
* <p>Defaults to <tt>"number"</tt>.
*/
public void setNumberFormat(String numberFormat) {
@@ -1034,11 +1033,38 @@
* only influenced the result of {@code myBool?string}.
*/
public void setBooleanFormat(String booleanFormat) {
+ validateBooleanFormat(booleanFormat);
+ this.booleanFormat = booleanFormat;
+ properties.setProperty(BOOLEAN_FORMAT_KEY, booleanFormat);
+ }
+
+ /**
+ * @throws IllegalArgumentException If the format string has unrecognized format
+ */
+ private static void validateBooleanFormat(String booleanFormat) {
+ parseOrValidateBooleanFormat(booleanFormat, true);
+ }
+
+ /**
+ * @return {@code null} for legacy default (not set in effect), empty array if the {@link CFormat} should be used,
+ * and an array of {@code [trueString, falseString]} otherwise.
+ *
+ * @throws IllegalArgumentException If the format string has unrecognized format
+ */
+ static String[] parseBooleanFormat(String booleanFormat) {
+ return parseOrValidateBooleanFormat(booleanFormat, false);
+ }
+
+ private static String[] parseOrValidateBooleanFormat(String booleanFormat, boolean validateOnly) {
NullArgumentException.check("booleanFormat", booleanFormat);
- if (booleanFormat.equals(C_TRUE_FALSE) || booleanFormat.equals(C_FORMAT_STRING)) {
- booleanFormatCommaSplitTrueSide = null;
- booleanFormatCommaSplitFalseSide = null;
+ if (booleanFormat.equals(C_FORMAT_STRING)) {
+ if (validateOnly) {
+ return null;
+ }
+ return CollectionUtils.EMPTY_STRING_ARRAY;
+ } else if (booleanFormat.equals(BOOLEAN_FORMAT_LEGACY_DEFAULT)) {
+ return null;
} else {
int commaIdx = booleanFormat.indexOf(',');
if (commaIdx == -1) {
@@ -1047,12 +1073,14 @@
"or it must be \"" + C_FORMAT_STRING + "\", but it was " +
StringUtil.jQuote(booleanFormat) + ".");
}
- booleanFormatCommaSplitTrueSide = booleanFormat.substring(0, commaIdx);
- booleanFormatCommaSplitFalseSide = booleanFormat.substring(commaIdx + 1);
+ if (validateOnly) {
+ return null;
+ }
+ return new String[] {
+ booleanFormat.substring(0, commaIdx),
+ booleanFormat.substring(commaIdx + 1)
+ };
}
-
- this.booleanFormat = booleanFormat;
- properties.setProperty(BOOLEAN_FORMAT_KEY, booleanFormat);
}
/**
@@ -1063,32 +1091,6 @@
}
/**
- * Non-{@code null} if the {@link #setBooleanFormat(String)} boolean_format} setting is comma separated true, and
- * false strings.
- *
- * @since 2.3.32
- */
- String getBooleanFormatCommaSplitTrueSide() {
- if (booleanFormat != null) {
- return booleanFormatCommaSplitTrueSide;
- }
- return parent != null ? parent.getBooleanFormatCommaSplitTrueSide() : null;
- }
-
- /**
- * Non-{@code null} if the {@link #setBooleanFormat(String)} boolean_format} setting is comma separated true, and
- * false strings.
- *
- * @since 2.3.32
- */
- String getBooleanFormatCommaSplitFalseSide() {
- if (booleanFormat != null) {
- return booleanFormatCommaSplitFalseSide;
- }
- return parent != null ? parent.getBooleanFormatCommaSplitFalseSide() : null;
- }
-
- /**
* Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}.
*
* @since 2.3.24
diff --git a/src/main/java/freemarker/core/Environment.java b/src/main/java/freemarker/core/Environment.java
index a56d9dd..0bd264b 100644
--- a/src/main/java/freemarker/core/Environment.java
+++ b/src/main/java/freemarker/core/Environment.java
@@ -1691,9 +1691,9 @@
}
/**
- * Returns the {@link TemplateNumberFormat} used for the <tt>c</tt> built-in currently uses in this environment.
+ * Returns the {@link TemplateNumberFormat} that {@code ?c}/{@code ?cn} uses.
* Calling this method for many times is fine, as it internally caches the result object.
- * Remember that {@link TemplateNumberFormat}-s are not thread-safe objects, so the resulting object should only
+ * Remember that {@link TemplateNumberFormat}-s aren't thread-safe objects, so the resulting object should only
* be used in the same thread where this {@link Environment} runs.
*
* @since 2.3.32
@@ -1729,6 +1729,7 @@
if (prevCFormat != cFormat) {
cTemplateNumberFormat = null;
cTemplateNumberFormatWithPre2331IcIBug = null;
+ cNumberFormat = null;
if (cachedTemplateNumberFormats != null) {
cachedTemplateNumberFormats.remove(C_FORMAT_STRING);
cachedTemplateNumberFormats.remove(COMPUTER_FORMAT_STRING);
@@ -1812,7 +1813,7 @@
return new _ErrorDescriptionBuilder(
"Can't convert boolean to string automatically, because the \"", BOOLEAN_FORMAT_KEY ,"\" setting was ",
new _DelayedJQuote(getBooleanFormat()),
- (getBooleanFormat().equals(C_TRUE_FALSE)
+ (getBooleanFormat().equals(BOOLEAN_FORMAT_LEGACY_DEFAULT)
? ", which is the legacy deprecated default, and we treat it as if no format was set. "
+ "This is the default configuration; you should provide the format explicitly for each "
+ "place where you print a boolean."
@@ -1869,17 +1870,19 @@
}
private void cacheTrueAndFalseStrings() {
- String spitTrueSide = getBooleanFormatCommaSplitTrueSide();
- if (spitTrueSide != null) {
- cachedTrueString = spitTrueSide;
- cachedFalseString = getBooleanFormatCommaSplitFalseSide();
- } else if (getBooleanFormat().equals(C_FORMAT_STRING)) {
- CFormat cFormat = getCFormat();
- cachedTrueString = cFormat.getTrueString();
- cachedFalseString = cFormat.getFalseString();
+ String[] parsedBooleanFormat = parseBooleanFormat(getBooleanFormat());
+ if (parsedBooleanFormat != null) {
+ if (parsedBooleanFormat.length == 0) {
+ CFormat cFormat = getCFormat();
+ cachedTrueString = cFormat.getTrueString();
+ cachedFalseString = cFormat.getFalseString();
+ } else {
+ cachedTrueString = parsedBooleanFormat[0];
+ cachedFalseString = parsedBooleanFormat[1];
+ }
} else {
- // This happens for C_TRUE_FALSE deliberately. That's the default for BC, but it's not a good default for human
- // audience formatting, so we pretend that it wasn't set.
+ // This happens for BOOLEAN_FORMAT_LEGACY_DEFAULT deliberately. That's the default for BC, but it's not a
+ // good default for human audience formatting, so we pretend that it wasn't set.
cachedTrueString = null;
cachedFalseString = null;
}
@@ -2410,7 +2413,7 @@
}
/**
- * Similar to {@link #getLocalVariable(String)}, but might returns {@link TemplateNullModel}. Only used internally,
+ * Similar to {@link #getLocalVariable(String)}, but might return {@link TemplateNullModel}. Only used internally,
* as {@link TemplateNullModel} is internal.
*
* @since 2.3.29
diff --git a/src/main/java/freemarker/core/MarkupOutputFormat.java b/src/main/java/freemarker/core/MarkupOutputFormat.java
index e8b3d96..c947c93 100644
--- a/src/main/java/freemarker/core/MarkupOutputFormat.java
+++ b/src/main/java/freemarker/core/MarkupOutputFormat.java
@@ -91,7 +91,7 @@
/**
* Returns the content as markup text; never {@code null}. If this {@link TemplateMarkupOutputModel} was created
- * with {@link #fromMarkup(String)}, it might returns the original markup text literally, but this is not required
+ * with {@link #fromMarkup(String)}, it might return the original markup text literally, but this is not required
* as far as the returned markup means the same. If this {@link TemplateMarkupOutputModel} wasn't created
* with {@link #fromMarkup(String)} and it doesn't yet have the markup, it has to generate the markup now.
*/
diff --git a/src/main/java/freemarker/core/StandardCFormats.java b/src/main/java/freemarker/core/StandardCFormats.java
new file mode 100644
index 0000000..aa56ccb
--- /dev/null
+++ b/src/main/java/freemarker/core/StandardCFormats.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 freemarker.core;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+final class StandardCFormats {
+ private StandardCFormats() {
+ }
+
+ static final Map<String, CFormat> STANDARD_C_FORMATS;
+ static {
+ Map<String, CFormat> map = new LinkedHashMap<>();
+ addStandardCFormat(map, JavaScriptOrJSONCFormat.INSTANCE);
+ addStandardCFormat(map, JSONCFormat.INSTANCE);
+ addStandardCFormat(map, JavaScriptCFormat.INSTANCE);
+ addStandardCFormat(map, JavaCFormat.INSTANCE);
+ addStandardCFormat(map, XSCFormat.INSTANCE);
+ addStandardCFormat(map, LegacyCFormat.INSTANCE);
+ STANDARD_C_FORMATS = Collections.unmodifiableMap(map);
+ }
+
+ private static void addStandardCFormat(Map<String, CFormat> map, CFormat cFormat) {
+ map.put(cFormat.getName(), cFormat);
+ }
+
+}
diff --git a/src/main/java/freemarker/core/_StandardCLanguages.java b/src/main/java/freemarker/core/_StandardCLanguages.java
deleted file mode 100644
index 9a22e7c..0000000
--- a/src/main/java/freemarker/core/_StandardCLanguages.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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 freemarker.core;
-
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-final class StandardCFormats {
- private StandardCFormats() {
- }
-
- static final Map<String, CFormat> STANDARD_C_FORMATS = new LinkedHashMap<>();
- static {
- addStandardCFormat(JavaScriptOrJSONCFormat.INSTANCE);
- addStandardCFormat(JSONCFormat.INSTANCE);
- addStandardCFormat(JavaScriptCFormat.INSTANCE);
- addStandardCFormat(JavaCFormat.INSTANCE);
- addStandardCFormat(XSCFormat.INSTANCE);
- addStandardCFormat(LegacyCFormat.INSTANCE);
- }
-
- private static void addStandardCFormat(CFormat cFormat) {
- STANDARD_C_FORMATS.put(cFormat.getName(), cFormat);
- }
-
-}
diff --git a/src/main/java/freemarker/ext/beans/BeansWrapper.java b/src/main/java/freemarker/ext/beans/BeansWrapper.java
index 5ac4ea1..47eb5c7 100644
--- a/src/main/java/freemarker/ext/beans/BeansWrapper.java
+++ b/src/main/java/freemarker/ext/beans/BeansWrapper.java
@@ -152,7 +152,7 @@
/**
* {@link String} class name to {@link StaticModel} cache.
* This object only belongs to a single {@link BeansWrapper}.
- * This has to be final as {@link #getStaticModels()} might returns it any time and then it has to remain a good
+ * This has to be final as {@link #getStaticModels()} might return it any time and then it has to remain a good
* reference.
*/
private final StaticModels staticModels;
@@ -160,7 +160,7 @@
/**
* {@link String} class name to {@link EnumerationModel} cache.
* This object only belongs to a single {@link BeansWrapper}.
- * This has to be final as {@link #getStaticModels()} might returns it any time and then it has to remain a good
+ * This has to be final as {@link #getStaticModels()} might return it any time and then it has to remain a good
* reference.
*/
private final ClassBasedModelFactory enumModels;
@@ -260,7 +260,7 @@
* </ul>
*
* <p>Note that the version will be normalized to the lowest version where the same incompatible
- * {@link BeansWrapper} improvements were already present, so {@link #getIncompatibleImprovements()} might returns
+ * {@link BeansWrapper} improvements were already present, so {@link #getIncompatibleImprovements()} might return
* a lower version than what you have specified.
*
* @since 2.3.21
diff --git a/src/main/java/freemarker/ext/beans/BeansWrapperConfiguration.java b/src/main/java/freemarker/ext/beans/BeansWrapperConfiguration.java
index ff43033..5daaa90 100644
--- a/src/main/java/freemarker/ext/beans/BeansWrapperConfiguration.java
+++ b/src/main/java/freemarker/ext/beans/BeansWrapperConfiguration.java
@@ -63,7 +63,7 @@
* See the corresponding parameter of {@link BeansWrapper#BeansWrapper(Version)}. Not {@code null}. Note
* that the version will be normalized to the lowest version where the same incompatible
* {@link BeansWrapper} improvements were already present, so for the returned instance
- * {@link #getIncompatibleImprovements()} might returns a lower version than what you have specified
+ * {@link #getIncompatibleImprovements()} might return a lower version than what you have specified
* here.
* @param isIncompImprsAlreadyNormalized
* Tells if the {@code incompatibleImprovements} parameter contains an <em>already normalized</em> value.
diff --git a/src/main/java/freemarker/template/_TemplateAPI.java b/src/main/java/freemarker/template/_TemplateAPI.java
index 0f7f23b..8fa3250 100644
--- a/src/main/java/freemarker/template/_TemplateAPI.java
+++ b/src/main/java/freemarker/template/_TemplateAPI.java
@@ -41,7 +41,7 @@
*/
public class _TemplateAPI {
// ATTENTION! Don't refer to other classes in the static initializer of this class! Fields that need that must be
- // moved into separate class, as it was done in _VersionInts, and _ObjectWrappers, to avoid class init deadlocks.
+ // moved into a separate class, to avoid class init deadlocks.
public static void checkVersionNotNullAndSupported(Version incompatibleImprovements) {
NullArgumentException.check("incompatibleImprovements", incompatibleImprovements);
diff --git a/src/main/java/freemarker/template/utility/CollectionUtils.java b/src/main/java/freemarker/template/utility/CollectionUtils.java
index 814fd1f..a164286 100644
--- a/src/main/java/freemarker/template/utility/CollectionUtils.java
+++ b/src/main/java/freemarker/template/utility/CollectionUtils.java
@@ -26,6 +26,8 @@
public static final Object[] EMPTY_OBJECT_ARRAY = new Object[] { };
+ public static final String[] EMPTY_STRING_ARRAY = new String[] { };
+
public static final Class[] EMPTY_CLASS_ARRAY = new Class[] { };
/**
diff --git a/src/main/java/freemarker/template/utility/StringUtil.java b/src/main/java/freemarker/template/utility/StringUtil.java
index 51f22a7..6d5f3fa 100644
--- a/src/main/java/freemarker/template/utility/StringUtil.java
+++ b/src/main/java/freemarker/template/utility/StringUtil.java
@@ -933,7 +933,7 @@
} else {
b.append(c);
}
- } // for each characters
+ } // for each character
b.append('"');
return b.toString();
}
@@ -1316,24 +1316,26 @@
c = s.charAt(i);
}
} // if has to be escaped
- } // for each characters
+ } // for each character
return quote ? '"' + s + '"' : s;
}
/**
* Escapes a {@link String} to be safely insertable into a JavaScript string literal; for more see
- * {@link #jsStringEnc(String, JsStringEncCompatibility, JsStringEncQuotation) jsStringEnc(s, false, QuotationMode.NONE)}.
+ * {@link #jsStringEnc(String, JsStringEncCompatibility, JsStringEncQuotation)
+ * jsStringEnc(s, JsStringEncCompatibility.JAVA_SCRIPT, null)}.
*/
public static String javaScriptStringEnc(String s) {
- return jsStringEnc(s, false);
+ return jsStringEnc(s, JsStringEncCompatibility.JAVA_SCRIPT);
}
/**
* Escapes a {@link String} to be safely insertable into a JSON string literal; for more see
- * {@link #jsStringEnc(String, boolean) jsStringEnc(s, true)}.
+ * {@link #jsStringEnc(String, JsStringEncCompatibility, JsStringEncQuotation)
+ * jsStringEnc(s, JsStringEncCompatibility.JSON, null)}.
*/
public static String jsonStringEnc(String s) {
- return jsStringEnc(s, true);
+ return jsStringEnc(s, JsStringEncCompatibility.JSON);
}
private static final int NO_ESC = 0;
@@ -1342,15 +1344,28 @@
/**
* Escapes a {@link String} to be safely insertable into a JSON or JavaScript string literal; for more see
- * {@link #jsStringEnc(String, JsStringEncCompatibility, JsStringEncQuotation) jsStringEnc(s, json, QuotationMode.NONE)}.
+ * {@link #jsStringEnc(String, JsStringEncCompatibility, JsStringEncQuotation)
+ * jsStringEnc(s, json ? JsStringEncCompatibility.JSON : JsStringEncCompatibility.JAVA_SCRIPT, null)}.
*
* @since 2.3.20
+ * @deprecated Use {@link #jsStringEnc(String, JsStringEncCompatibility)} instead.
*/
+ @Deprecated
public static String jsStringEnc(String s, boolean json) {
return jsStringEnc(s, json ? JsStringEncCompatibility.JSON : JsStringEncCompatibility.JAVA_SCRIPT, null);
}
/**
+ * Escapes a {@link String} to be safely insertable into a JSON or JavaScript string literal; for more see
+ * {@link #jsStringEnc(String, JsStringEncCompatibility, JsStringEncQuotation) jsStringEnc(s, compatibility, null)}.
+ *
+ * @since 2.3.32
+ */
+ public static String jsStringEnc(String s, JsStringEncCompatibility compatibility) {
+ return jsStringEnc(s, compatibility, null);
+ }
+
+ /**
* Escapes a {@link String} to be safely insertable into a JavaScript or a JSON string literal, and if the 3rd
* argument is {@code true}, also adds quotation marks around it.
* If instead the caller ensures that the quotation marks are there, then in JSON mode (2nd argument), the quotation
@@ -1520,7 +1535,7 @@
// Needs no escaping
if (sb != null) sb.append(c);
- } // for each characters
+ } // for each character
if (quotation != null) {
sb.append(quotation.getSymbol());
diff --git a/src/manual/en_US/book.xml b/src/manual/en_US/book.xml
index 2f9d3b7..8569625 100644
--- a/src/manual/en_US/book.xml
+++ b/src/manual/en_US/book.xml
@@ -10604,7 +10604,7 @@
linkend="gloss.unicode">UNICODE</link> text" (UTF-16). Nonetheless,
there are situations when it must deal with <link
linkend="gloss.charset">charsets</link>, because it has to exchange
- data with the outer world that may uses various other charsets.</para>
+ data with the outer world that may use various other charsets.</para>
<section>
<title>The charset of the input</title>
@@ -16269,7 +16269,7 @@
<title>is_infinite</title>
<indexterm>
- <primary>is_infinte built-in</primary>
+ <primary>is_infinite built-in</primary>
</indexterm>
<indexterm>
@@ -28786,7 +28786,7 @@
<answer>
<para>FreeMarker uses the locale-sensitive number formatting
capability of the Java platform. The default number format for
- your locale may uses grouping or other formatting. If you don't
+ your locale may use grouping or other formatting. If you don't
want that, you have to override the number format suggested by the
Java platform with the <literal>number_format</literal> <link
linkend="pgui_config_settings">FreeMarker setting</link>. For
diff --git a/src/manual/zh_CN/book.xml b/src/manual/zh_CN/book.xml
index 81ef7fb..e03ff44 100644
--- a/src/manual/zh_CN/book.xml
+++ b/src/manual/zh_CN/book.xml
@@ -20,10 +20,7 @@
<book conformance="docgen" version="5.0" xml:lang="en"
xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
- xmlns:ns5="http://www.w3.org/1999/xhtml"
- xmlns:ns4="http://www.w3.org/2000/svg"
- xmlns:ns3="http://www.w3.org/1998/Math/MathML"
- xmlns:ns="http://docbook.org/ns/docbook">
+>
<info>
<title>FreeMarker 手册</title>
@@ -11427,7 +11424,7 @@
<title>is_infinite</title>
<indexterm>
- <primary>is_infinte built-in</primary>
+ <primary>is_infinite built-in</primary>
</indexterm>
<indexterm>
diff --git a/src/test/java/freemarker/core/BooleanFormatEnvironmentCachingTest.java b/src/test/java/freemarker/core/BooleanFormatEnvironmentCachingTest.java
index d8ca4d8..0feb90c 100644
--- a/src/test/java/freemarker/core/BooleanFormatEnvironmentCachingTest.java
+++ b/src/test/java/freemarker/core/BooleanFormatEnvironmentCachingTest.java
@@ -45,13 +45,12 @@
+ "<#setting cFormat='JSON'>${true} ${true} ${false} ${false} "
+ "<#setting booleanFormat='y,n'>${true} ${true} ${false} ${false} "
+ "<#setting cFormat='Java'>${true} ${true} ${false} ${false} "
- + "<#setting booleanFormat='c'>${true} ${true} ${false} ${false} ",
+ + "<#setting booleanFormat='c'>${true} ${true} ${false} ${false}",
""
+ "TRUE TRUE FALSE FALSE "
+ "true true false false "
+ "y y n n "
+ "y y n n "
- + "true true false false "
- + "");
+ + "true true false false");
}
}
\ No newline at end of file
diff --git a/src/test/java/freemarker/core/CFormatTemplateTest.java b/src/test/java/freemarker/core/CFormatTemplateTest.java
index 414a901..fd8a66f 100644
--- a/src/test/java/freemarker/core/CFormatTemplateTest.java
+++ b/src/test/java/freemarker/core/CFormatTemplateTest.java
@@ -70,4 +70,10 @@
+ "Java: \"a'b\\\"c\\u0001\" ");
}
+ @Test
+ public void testUnsafeSetting() throws TemplateException, IOException {
+ assertErrorContains("<#setting c_format='com.example.ExploitCFormat()'>", "not allowed");
+ assertErrorContains("<#setting cFormat='com.example.ExploitCFormat()'>", "not allowed");
+ }
+
}
diff --git a/src/test/java/freemarker/core/NumberBiTest.java b/src/test/java/freemarker/core/NumberBiTest.java
index 3f3bd44..e4c1a8c 100644
--- a/src/test/java/freemarker/core/NumberBiTest.java
+++ b/src/test/java/freemarker/core/NumberBiTest.java
@@ -51,10 +51,6 @@
assertNumberBi("+1", "1");
}
- private void assertThrowsNumberFormatException(String s) {
- assertErrorContains("${'" + s + "'?number}", NonNumericalException.class, "\"" + s + "\"");
- }
-
private final void assertNumberBi(String input, String output) throws TemplateException, IOException {
assertOutput("${'" + input + "'?number?c}", output);
}
diff --git a/src/test/java/freemarker/template/ConfigurationTest.java b/src/test/java/freemarker/template/ConfigurationTest.java
index 756b3fa..72287e6 100644
--- a/src/test/java/freemarker/template/ConfigurationTest.java
+++ b/src/test/java/freemarker/template/ConfigurationTest.java
@@ -314,7 +314,7 @@
assertTrue(cfg.isCFormatExplicitlySet());
//
cfg.unsetCFormat();
- assertFalse(cfg.isTemplateLookupStrategyExplicitlySet());
+ assertFalse(cfg.isCFormatExplicitlySet());
}
public void testTemplateLoadingErrors() throws Exception {
@@ -1877,8 +1877,10 @@
assertEquals(3, alg.getDefaultTerminatorLength());
assertNull(alg.getDefaultMTerminator());
assertNull(alg.getDefaultMTerminatorLength());
- assertEquals(DefaultTruncateBuiltinAlgorithm.DEFAULT_WORD_BOUNDARY_MIN_LENGTH,
- alg.getWordBoundaryMinLength());
+ assertEquals(
+ DefaultTruncateBuiltinAlgorithm.DEFAULT_WORD_BOUNDARY_MIN_LENGTH,
+ alg.getWordBoundaryMinLength(),
+ 0);
}
{
@@ -1895,8 +1897,10 @@
assertEquals("markupOutput(format=HTML, markup=<span class=trunc>...</span>)",
alg.getDefaultMTerminator().toString());
assertEquals(Integer.valueOf(3), alg.getDefaultMTerminatorLength());
- assertEquals(DefaultTruncateBuiltinAlgorithm.DEFAULT_WORD_BOUNDARY_MIN_LENGTH,
- alg.getWordBoundaryMinLength());
+ assertEquals(
+ DefaultTruncateBuiltinAlgorithm.DEFAULT_WORD_BOUNDARY_MIN_LENGTH,
+ alg.getWordBoundaryMinLength(),
+ 0);
}
{
@@ -1931,8 +1935,8 @@
for (CFormat standardCFormat : new CFormat[] {
LegacyCFormat.INSTANCE,
- JSONCFormat.INSTANCE, JavaScriptCFormat.INSTANCE, JavaCFormat.INSTANCE,
- XSCFormat.INSTANCE
+ JSONCFormat.INSTANCE, JavaScriptCFormat.INSTANCE, JavaScriptOrJSONCFormat.INSTANCE,
+ JavaCFormat.INSTANCE, XSCFormat.INSTANCE
}) {
cfg.setSetting(Configuration.C_FORMAT_KEY, standardCFormat.getName());
assertSame(standardCFormat, cfg.getCFormat());