This is an automated email from the ASF dual-hosted git repository.
ddekany pushed a commit to branch 2.3-gae
in repository https://gitbox.apache.org/repos/asf/freemarker.git
The following commit(s) were added to refs/heads/2.3-gae by this push:
new ea1c5eaf Mostly CFormat-related code cleanup (things spotted during
forward porting into FM3)
ea1c5eaf is described below
commit ea1c5eafe494399b3066ad1ecb62e7ab9b8ae42a
Author: ddekany <[email protected]>
AuthorDate: Sun Jan 1 14:29:33 2023 +0100
Mostly CFormat-related code cleanup (things spotted during forward porting
into FM3)
---
.../java/freemarker/core/ArithmeticEngine.java | 2 +-
.../freemarker/core/CTemplateNumberFormat.java | 6 +-
src/main/java/freemarker/core/Configurable.java | 88 +++++++++++-----------
src/main/java/freemarker/core/Environment.java | 31 ++++----
.../java/freemarker/core/MarkupOutputFormat.java | 2 +-
...andardCLanguages.java => StandardCFormats.java} | 21 +++---
.../java/freemarker/ext/beans/BeansWrapper.java | 6 +-
.../ext/beans/BeansWrapperConfiguration.java | 2 +-
.../java/freemarker/template/_TemplateAPI.java | 2 +-
.../template/utility/CollectionUtils.java | 2 +
.../freemarker/template/utility/StringUtil.java | 31 ++++++--
src/manual/en_US/book.xml | 6 +-
src/manual/zh_CN/book.xml | 7 +-
.../core/BooleanFormatEnvironmentCachingTest.java | 5 +-
.../java/freemarker/core/CFormatTemplateTest.java | 6 ++
src/test/java/freemarker/core/NumberBiTest.java | 4 -
.../freemarker/template/ConfigurationTest.java | 18 +++--
17 files changed, 132 insertions(+), 107 deletions(-)
diff --git a/src/main/java/freemarker/core/ArithmeticEngine.java
b/src/main/java/freemarker/core/ArithmeticEngine.java
index 468f5e40..dc946d2c 100644
--- a/src/main/java/freemarker/core/ArithmeticEngine.java
+++ b/src/main/java/freemarker/core/ArithmeticEngine.java
@@ -116,7 +116,7 @@ public abstract class ArithmeticEngine {
@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 dc662b7a..3df4177d 100644
--- a/src/main/java/freemarker/core/CTemplateNumberFormat.java
+++ b/src/main/java/freemarker/core/CTemplateNumberFormat.java
@@ -136,11 +136,10 @@ final class CTemplateNumberFormat extends
TemplateNumberFormat {
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 @@ final class CTemplateNumberFormat extends
TemplateNumberFormat {
return "c";
}
-
}
diff --git a/src/main/java/freemarker/core/Configurable.java
b/src/main/java/freemarker/core/Configurable.java
index 0e03b220..a70e247e 100644
--- a/src/main/java/freemarker/core/Configurable.java
+++ b/src/main/java/freemarker/core/Configurable.java
@@ -66,6 +66,7 @@ import freemarker.template.TemplateModel;
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 @@ import freemarker.template.utility.StringUtil;
* 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 @@ public class Configurable {
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 @@ public class Configurable {
// 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 @@ public class Configurable {
}
/**
- * 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 @@ public class Configurable {
* <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 @@ public class Configurable {
* <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 @@ public class Configurable {
* 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 @@ public class Configurable {
"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);
}
/**
@@ -1062,32 +1090,6 @@ public class Configurable {
return booleanFormat != null ? booleanFormat :
parent.getBooleanFormat();
}
- /**
- * 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}.
*
diff --git a/src/main/java/freemarker/core/Environment.java
b/src/main/java/freemarker/core/Environment.java
index a56d9ddf..0bd264bb 100644
--- a/src/main/java/freemarker/core/Environment.java
+++ b/src/main/java/freemarker/core/Environment.java
@@ -1691,9 +1691,9 @@ public final class Environment extends Configurable {
}
/**
- * 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 @@ public final class Environment extends Configurable {
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 @@ public final class Environment extends Configurable {
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 @@ public final class Environment extends Configurable {
}
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 @@ public final class Environment extends Configurable {
}
/**
- * 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 e8b3d969..c947c93e 100644
--- a/src/main/java/freemarker/core/MarkupOutputFormat.java
+++ b/src/main/java/freemarker/core/MarkupOutputFormat.java
@@ -91,7 +91,7 @@ public abstract class MarkupOutputFormat<MO extends
TemplateMarkupOutputModel> e
/**
* 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/_StandardCLanguages.java
b/src/main/java/freemarker/core/StandardCFormats.java
similarity index 58%
rename from src/main/java/freemarker/core/_StandardCLanguages.java
rename to src/main/java/freemarker/core/StandardCFormats.java
index 9a22e7ca..aa56ccb1 100644
--- a/src/main/java/freemarker/core/_StandardCLanguages.java
+++ b/src/main/java/freemarker/core/StandardCFormats.java
@@ -19,6 +19,7 @@
package freemarker.core;
+import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -26,18 +27,20 @@ final class StandardCFormats {
private StandardCFormats() {
}
- static final Map<String, CFormat> STANDARD_C_FORMATS = new
LinkedHashMap<>();
+ static final Map<String, CFormat> STANDARD_C_FORMATS;
static {
- addStandardCFormat(JavaScriptOrJSONCFormat.INSTANCE);
- addStandardCFormat(JSONCFormat.INSTANCE);
- addStandardCFormat(JavaScriptCFormat.INSTANCE);
- addStandardCFormat(JavaCFormat.INSTANCE);
- addStandardCFormat(XSCFormat.INSTANCE);
- addStandardCFormat(LegacyCFormat.INSTANCE);
+ 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(CFormat cFormat) {
- STANDARD_C_FORMATS.put(cFormat.getName(), cFormat);
+ private static void addStandardCFormat(Map<String, CFormat> map, CFormat
cFormat) {
+ map.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 5ac4ea1f..47eb5c72 100644
--- a/src/main/java/freemarker/ext/beans/BeansWrapper.java
+++ b/src/main/java/freemarker/ext/beans/BeansWrapper.java
@@ -152,7 +152,7 @@ public class BeansWrapper implements RichObjectWrapper,
WriteProtectable {
/**
* {@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 @@ public class BeansWrapper implements RichObjectWrapper,
WriteProtectable {
/**
* {@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 @@ public class BeansWrapper implements RichObjectWrapper,
WriteProtectable {
* </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 ff43033d..5daaa909 100644
--- a/src/main/java/freemarker/ext/beans/BeansWrapperConfiguration.java
+++ b/src/main/java/freemarker/ext/beans/BeansWrapperConfiguration.java
@@ -63,7 +63,7 @@ public abstract class BeansWrapperConfiguration implements
Cloneable {
* 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 0f7f23b4..8fa3250d 100644
--- a/src/main/java/freemarker/template/_TemplateAPI.java
+++ b/src/main/java/freemarker/template/_TemplateAPI.java
@@ -41,7 +41,7 @@ import freemarker.template.utility.NullArgumentException;
*/
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 814fd1f0..a164286a 100644
--- a/src/main/java/freemarker/template/utility/CollectionUtils.java
+++ b/src/main/java/freemarker/template/utility/CollectionUtils.java
@@ -26,6 +26,8 @@ public class CollectionUtils {
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 51f22a73..6d5f3fa0 100644
--- a/src/main/java/freemarker/template/utility/StringUtil.java
+++ b/src/main/java/freemarker/template/utility/StringUtil.java
@@ -933,7 +933,7 @@ public class StringUtil {
} else {
b.append(c);
}
- } // for each characters
+ } // for each character
b.append('"');
return b.toString();
}
@@ -1316,24 +1316,26 @@ public class StringUtil {
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,14 +1344,27 @@ public class StringUtil {
/**
* 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.
@@ -1520,7 +1535,7 @@ public class StringUtil {
// 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 2f9d3b7d..8569625e 100644
--- a/src/manual/en_US/book.xml
+++ b/src/manual/en_US/book.xml
@@ -10604,7 +10604,7 @@ cfg.setNumberFormat("@ua 0.####;;
roundingMode=halfUp");</programlisting>
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 @@ rif: foo XYr baar</programlisting>
<title>is_infinite</title>
<indexterm>
- <primary>is_infinte built-in</primary>
+ <primary>is_infinite built-in</primary>
</indexterm>
<indexterm>
@@ -28786,7 +28786,7 @@ End book</programlisting>
<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 81ef7fb4..e03ff448 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 @@ rif: foo XYr baar</programlisting>
<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 d8ca4d81..0feb90c8 100644
--- a/src/test/java/freemarker/core/BooleanFormatEnvironmentCachingTest.java
+++ b/src/test/java/freemarker/core/BooleanFormatEnvironmentCachingTest.java
@@ -45,13 +45,12 @@ public class BooleanFormatEnvironmentCachingTest extends
TemplateTest {
+ "<#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 414a9011..fd8a66fa 100644
--- a/src/test/java/freemarker/core/CFormatTemplateTest.java
+++ b/src/test/java/freemarker/core/CFormatTemplateTest.java
@@ -70,4 +70,10 @@ public class CFormatTemplateTest extends TemplateTest {
+ "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 3f3bd446..e4c1a8ce 100644
--- a/src/test/java/freemarker/core/NumberBiTest.java
+++ b/src/test/java/freemarker/core/NumberBiTest.java
@@ -51,10 +51,6 @@ public class NumberBiTest extends TemplateTest {
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 756b3fae..72287e66 100644
--- a/src/test/java/freemarker/template/ConfigurationTest.java
+++ b/src/test/java/freemarker/template/ConfigurationTest.java
@@ -314,7 +314,7 @@ public class ConfigurationTest extends TestCase {
assertTrue(cfg.isCFormatExplicitlySet());
//
cfg.unsetCFormat();
- assertFalse(cfg.isTemplateLookupStrategyExplicitlySet());
+ assertFalse(cfg.isCFormatExplicitlySet());
}
public void testTemplateLoadingErrors() throws Exception {
@@ -1877,8 +1877,10 @@ public class ConfigurationTest extends TestCase {
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 @@ public class ConfigurationTest extends TestCase {
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 @@ public class ConfigurationTest extends TestCase {
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());