You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@freemarker.apache.org by dd...@apache.org on 2022/12/30 23:26:37 UTC
[freemarker] 02/02: CFormat: Replace two Default23*CFormat classes with a single LegacyCFormat.
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
commit 9e14cb0b55bd2ae266af0b6a702e9f8ef50eb6f8
Author: ddekany <dd...@apache.org>
AuthorDate: Fri Dec 30 23:47:52 2022 +0100
CFormat: Replace two Default23*CFormat classes with a single LegacyCFormat.
---
.../freemarker/core/AbstractJSONLikeFormat.java | 3 +-
.../freemarker/core/AbstractLegacyCFormat.java | 104 -------------
src/main/java/freemarker/core/Configurable.java | 5 +-
.../java/freemarker/core/Default230CFormat.java | 73 ---------
.../java/freemarker/core/Default2321CFormat.java | 72 ---------
src/main/java/freemarker/core/Environment.java | 25 +--
src/main/java/freemarker/core/JavaCFormat.java | 4 +-
src/main/java/freemarker/core/LegacyCFormat.java | 173 +++++++++++++++++++++
src/main/java/freemarker/core/XSCFormat.java | 3 +-
.../java/freemarker/core/_StandardCLanguages.java | 3 +-
.../java/freemarker/template/Configuration.java | 16 +-
src/manual/en_US/book.xml | 80 +++++-----
src/test/java/freemarker/core/CustomCFormat.java | 4 +-
.../freemarker/template/ConfigurationTest.java | 21 ++-
14 files changed, 253 insertions(+), 333 deletions(-)
diff --git a/src/main/java/freemarker/core/AbstractJSONLikeFormat.java b/src/main/java/freemarker/core/AbstractJSONLikeFormat.java
index ad6b7349..7f305ff4 100644
--- a/src/main/java/freemarker/core/AbstractJSONLikeFormat.java
+++ b/src/main/java/freemarker/core/AbstractJSONLikeFormat.java
@@ -37,7 +37,8 @@ public abstract class AbstractJSONLikeFormat extends CFormat {
"Infinity", "-Infinity", "NaN",
"Infinity", "-Infinity", "NaN");
- private static final DecimalFormat LEGACY_NUMBER_FORMAT_PROTOTYPE = (DecimalFormat) Default230CFormat.LEGACY_NUMBER_FORMAT_PROTOTYPE.clone();
+ private static final DecimalFormat LEGACY_NUMBER_FORMAT_PROTOTYPE
+ = (DecimalFormat) LegacyCFormat.LEGACY_NUMBER_FORMAT_PROTOTYPE_2_3_0.clone();
static {
DecimalFormatSymbols symbols = LEGACY_NUMBER_FORMAT_PROTOTYPE.getDecimalFormatSymbols();
symbols.setInfinity("Infinity");
diff --git a/src/main/java/freemarker/core/AbstractLegacyCFormat.java b/src/main/java/freemarker/core/AbstractLegacyCFormat.java
deleted file mode 100644
index c564d144..00000000
--- a/src/main/java/freemarker/core/AbstractLegacyCFormat.java
+++ /dev/null
@@ -1,104 +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 freemarker.template.TemplateException;
-import freemarker.template.TemplateModelException;
-import freemarker.template.TemplateNumberModel;
-import freemarker.template.utility.StringUtil;
-import freemarker.template.utility.StringUtil.JsStringEncCompatibility;
-import freemarker.template.utility.StringUtil.JsStringEncQuotation;
-
-/**
- * Super class of {@link CFormat}-s that merely exist to mimic old {@code ?c} behavior for backward compatibility.
- *
- * <p><b>Experimental class!</b> This class is too new, and might will change over time. Therefore, for now
- * constructor and most methods are not exposed outside FreeMarker, and so you can't create a custom implementation.
- * The class itself and some members are exposed as they are needed for configuring FreeMarker.
- *
- * @since 2.3.32
- * @see AbstractJSONLikeFormat
- */
-public abstract class AbstractLegacyCFormat extends CFormat {
- // Visibility is not "protected" to avoid external implementations while this class is experimental.
- AbstractLegacyCFormat() {
- }
-
- @Override
- final String formatString(String s, Environment env) throws TemplateException {
- return StringUtil.jsStringEnc(
- s, JsStringEncCompatibility.JAVA_SCRIPT_OR_JSON, JsStringEncQuotation.QUOTATION_MARK);
- }
-
- @Override
- final TemplateNumberFormat getTemplateNumberFormat(Environment env) {
- return new LegacyCTemplateNumberFormat(env);
- }
-
- @Override
- String getTrueString() {
- return "true";
- }
-
- @Override
- String getFalseString() {
- return "false";
- }
-
- @Override
- final String getNullString() {
- return "null";
- }
-
- final class LegacyCTemplateNumberFormat extends JavaTemplateNumberFormat {
-
- public LegacyCTemplateNumberFormat(Environment env) {
- super(getLegacyNumberFormat(env), Environment.COMPUTER_FORMAT_STRING);
- }
-
- @Override
- public String formatToPlainText(TemplateNumberModel numberModel) throws UnformattableValueException,
- TemplateModelException {
- Number number = TemplateFormatUtil.getNonNullNumber(numberModel);
- return format(number);
- }
-
- @Override
- public boolean isLocaleBound() {
- return false;
- }
-
- @Override
- String format(Number number) throws UnformattableValueException {
- if (number instanceof Integer || number instanceof Long) {
- // Accelerate these fairly common cases
- return number.toString();
- }
- return super.format(number);
- }
-
- @Override
- public String getDescription() {
- return "LegacyC(" + super.getDescription() + ")";
- }
-
- }
-
-}
diff --git a/src/main/java/freemarker/core/Configurable.java b/src/main/java/freemarker/core/Configurable.java
index bb6ef998..0e03b220 100644
--- a/src/main/java/freemarker/core/Configurable.java
+++ b/src/main/java/freemarker/core/Configurable.java
@@ -702,8 +702,7 @@ public class Configurable {
* {@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"}. For lower it's {@code "default 2.3.31"} or
- * {@code "default 2.3.0"}.
+ * If that's 2.3.32 or higher, then it's {@code "JavaScript or JSON"}, otherwise it's {@code "legacy"}.
*
* @since 2.3.32
*/
@@ -2196,7 +2195,7 @@ public class Configurable {
* <br>String value: {@code "default"} (case insensitive) for the default (on {@link Configuration} only), or
* one of the predefined values {@code "JavaScript or JSON"}, {@code "JSON"},
* {@code "JavaScript"}, {@code "Java"}, {@code "XS"},
- * {@code "default 2.3.0"}, {@code "default 2.3.21"}, or
+ * {@code "legacy"}, or
* {@code "default"} (only allowed for {@link Configuration} instances) for the default value,
* or an <a href="#fm_obe">object builder expression</a> that gives a {@link CFormat} object.
*
diff --git a/src/main/java/freemarker/core/Default230CFormat.java b/src/main/java/freemarker/core/Default230CFormat.java
deleted file mode 100644
index 88749766..00000000
--- a/src/main/java/freemarker/core/Default230CFormat.java
+++ /dev/null
@@ -1,73 +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.text.DecimalFormat;
-import java.text.DecimalFormatSymbols;
-import java.text.NumberFormat;
-import java.util.Locale;
-
-import freemarker.template.Configuration;
-import freemarker.template.Version;
-
-/**
- * Corresponds to the behavior of {@code ?c} if
- * {@link Configuration#Configuration(Version) incompatible_improvements} is less than
- * {@linkplain Configuration#VERSION_2_3_21 2.3.21}.
- * The only good reason for using this is strict backward-compatibility.
- *
- * <p><b>Experimental class!</b> This class is too new, and might will change over time. Therefore, for now
- * constructor and most methods are not exposed outside FreeMarker, and so you can't create a custom implementation.
- * The class itself and some members are exposed as they are needed for configuring FreeMarker.
- *
- * @see Default2321CFormat
- * @see JSONCFormat
- *
- * @since 2.3.32
- */
-public final class Default230CFormat extends AbstractLegacyCFormat {
- public static final Default230CFormat INSTANCE = new Default230CFormat();
- public static final String NAME = "default 2.3.0";
-
- /**
- * "c" number format as it was before Incompatible Improvements 2.3.21.
- */
- static final DecimalFormat LEGACY_NUMBER_FORMAT_PROTOTYPE = new DecimalFormat(
- "0.################",
- new DecimalFormatSymbols(Locale.US));
- static {
- LEGACY_NUMBER_FORMAT_PROTOTYPE.setGroupingUsed(false);
- LEGACY_NUMBER_FORMAT_PROTOTYPE.setDecimalSeparatorAlwaysShown(false);
- }
-
- private Default230CFormat() {
- }
-
- @Override
- NumberFormat getLegacyNumberFormat(Environment env) {
- // Note: DecimalFormat-s aren't thread-safe, so you must clone the static field value.
- return (NumberFormat) LEGACY_NUMBER_FORMAT_PROTOTYPE.clone();
- }
-
- @Override
- public String getName() {
- return NAME;
- }
-}
diff --git a/src/main/java/freemarker/core/Default2321CFormat.java b/src/main/java/freemarker/core/Default2321CFormat.java
deleted file mode 100644
index c466769a..00000000
--- a/src/main/java/freemarker/core/Default2321CFormat.java
+++ /dev/null
@@ -1,72 +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.text.DecimalFormat;
-import java.text.DecimalFormatSymbols;
-import java.text.NumberFormat;
-
-import freemarker.template.Configuration;
-import freemarker.template.Version;
-
-/**
- * Corresponds to the behavior of {@code ?c} if
- * {@link Configuration#Configuration(Version) incompatible_improvements} is between
- * {@linkplain Configuration#VERSION_2_3_21 2.3.21} and {@linkplain Configuration#VERSION_2_3_31 2.3.31}.
- * The only good reason for using this is strict backward-compatibility.
- *
- * <p><b>Experimental class!</b> This class is too new, and might will change over time. Therefore, for now
- * constructor and most methods are not exposed outside FreeMarker, and so you can't create a custom implementation.
- * The class itself and some members are exposed as they are needed for configuring FreeMarker.
- *
- * @see Default230CFormat
- * @see JSONCFormat
- *
- * @since 2.3.32
- */
-public final class Default2321CFormat extends AbstractLegacyCFormat {
- public static final Default2321CFormat INSTANCE = new Default2321CFormat();
- public static final String NAME = "default 2.3.21";
-
- /**
- * "c" number format as it was starting from Incompatible Improvements 2.3.21.
- */
- private static final DecimalFormat LEGACY_NUMBER_FORMAT_PROTOTYPE = (DecimalFormat) Default230CFormat.LEGACY_NUMBER_FORMAT_PROTOTYPE.clone();
- static {
- DecimalFormatSymbols symbols = LEGACY_NUMBER_FORMAT_PROTOTYPE.getDecimalFormatSymbols();
- symbols.setInfinity("INF");
- symbols.setNaN("NaN");
- LEGACY_NUMBER_FORMAT_PROTOTYPE.setDecimalFormatSymbols(symbols);
- }
-
- private Default2321CFormat() {
- }
-
- @Override
- NumberFormat getLegacyNumberFormat(Environment env) {
- // Note: DecimalFormat-s aren't thread-safe, so you must clone the static field value.
- return (NumberFormat) LEGACY_NUMBER_FORMAT_PROTOTYPE.clone();
- }
-
- @Override
- public String getName() {
- return NAME;
- }
-}
diff --git a/src/main/java/freemarker/core/Environment.java b/src/main/java/freemarker/core/Environment.java
index c5be9e17..a56d9ddf 100644
--- a/src/main/java/freemarker/core/Environment.java
+++ b/src/main/java/freemarker/core/Environment.java
@@ -1679,7 +1679,13 @@ public final class Environment extends Configurable {
@Deprecated
public NumberFormat getCNumberFormat() {
if (cNumberFormat == null) {
- cNumberFormat = getCFormatWithPre2331IcIBug().getLegacyNumberFormat(this);
+ CFormat cFormat = getCFormat();
+ if (cFormat == LegacyCFormat.INSTANCE && configuration.getIncompatibleImprovements().intValue() < _VersionInts.V_2_3_31) {
+ // Emulate old bug
+ cNumberFormat = ((LegacyCFormat) cFormat).getLegacyNumberFormat(_VersionInts.V_2_3_20);
+ } else {
+ cNumberFormat = cFormat.getLegacyNumberFormat(this);
+ }
}
return cNumberFormat;
}
@@ -1705,20 +1711,17 @@ public final class Environment extends Configurable {
*/
private TemplateNumberFormat getCTemplateNumberFormatWithPre2331IcIBug() {
if (cTemplateNumberFormatWithPre2331IcIBug == null) {
- cTemplateNumberFormatWithPre2331IcIBug = getCFormatWithPre2331IcIBug().getTemplateNumberFormat(this);
+ CFormat cFormat = getCFormat();
+ if (cFormat == LegacyCFormat.INSTANCE && configuration.getIncompatibleImprovements().intValue() < _VersionInts.V_2_3_31) {
+ // Emulate old bug
+ cTemplateNumberFormatWithPre2331IcIBug = ((LegacyCFormat) cFormat).getTemplateNumberFormat(_VersionInts.V_2_3_20);
+ } else {
+ cTemplateNumberFormatWithPre2331IcIBug = cFormat.getTemplateNumberFormat(this);
+ }
}
return cTemplateNumberFormatWithPre2331IcIBug;
}
- private CFormat getCFormatWithPre2331IcIBug() {
- CFormat cFormat = getCFormat();
- if (cFormat == Default2321CFormat.INSTANCE
- && configuration.getIncompatibleImprovements().intValue() < _VersionInts.V_2_3_31) {
- return Default230CFormat.INSTANCE;
- }
- return cFormat;
- }
-
@Override
public void setCFormat(CFormat cFormat) {
CFormat prevCFormat = getCFormat();
diff --git a/src/main/java/freemarker/core/JavaCFormat.java b/src/main/java/freemarker/core/JavaCFormat.java
index 020378e0..64c6feb9 100644
--- a/src/main/java/freemarker/core/JavaCFormat.java
+++ b/src/main/java/freemarker/core/JavaCFormat.java
@@ -39,7 +39,9 @@ public final class JavaCFormat extends CFormat {
"Double.POSITIVE_INFINITY", "Double.NEGATIVE_INFINITY", "Double.NaN",
"Float.POSITIVE_INFINITY", "Float.NEGATIVE_INFINITY", "Float.NaN");
- private static final DecimalFormat LEGACY_NUMBER_FORMAT_PROTOTYPE = (DecimalFormat) Default230CFormat.LEGACY_NUMBER_FORMAT_PROTOTYPE.clone();
+ private static final DecimalFormat LEGACY_NUMBER_FORMAT_PROTOTYPE
+ = (DecimalFormat) LegacyCFormat.LEGACY_NUMBER_FORMAT_PROTOTYPE_2_3_0.clone();
+
static {
DecimalFormatSymbols symbols = LEGACY_NUMBER_FORMAT_PROTOTYPE.getDecimalFormatSymbols();
symbols.setInfinity("Double.POSITIVE_INFINITY");
diff --git a/src/main/java/freemarker/core/LegacyCFormat.java b/src/main/java/freemarker/core/LegacyCFormat.java
new file mode 100644
index 00000000..1f3d5886
--- /dev/null
+++ b/src/main/java/freemarker/core/LegacyCFormat.java
@@ -0,0 +1,173 @@
+/*
+ * 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.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.NumberFormat;
+import java.util.Locale;
+
+import freemarker.template.Configuration;
+import freemarker.template.TemplateException;
+import freemarker.template.TemplateModelException;
+import freemarker.template.TemplateNumberModel;
+import freemarker.template.Version;
+import freemarker.template._VersionInts;
+import freemarker.template.utility.StringUtil;
+
+/**
+ * Corresponds to the behavior of {@code ?c} before {@linkplain Configuration#VERSION_2_3_32 2.3.32} (when there
+ * were no {@link CFormat}-s yet). This only exists for strict backward-compatibility, otherwise avoid this, mostly
+ * because its number-to-string conversion sometimes do rounding, and infinity and NaN formatting has some glitches.
+ * This is the default of {@link Configurable#setCFormat(CFormat) c_format} if
+ * {@link Configuration#Configuration(Version) incompatible_improvements} is less than 2.3.32.
+ *
+ * <p>If {@link Configuration#Configuration(Version) incompatible_improvements} is at least
+ * 2.3.21, then infinity is formatted as {@code INF}, and NaN as
+ * {@code NaN}. If it's less, then infinity is formatted to the infinity character (U+221E), and NaN to the
+ * UNICODE replacement character (U+FFFD). But, because of an old bug that we emulate, this only applies to the behavior
+ * of {@code ?c}/{@code ?cn}, and not to the {@code "c"} and {@code "computer"}
+ * {@link Configurable#setNumberFormat(String) number_format}.
+ * The last uses the pre-2.3.21 format before {@link Configuration#Configuration(Version) incompatible_improvements}
+ * 2.3.31.
+ *
+ * <p><b>Experimental class!</b> This class is too new, and might will change over time. Therefore, for now
+ * constructor and most methods are not exposed outside FreeMarker, and so you can't create a custom implementation.
+ * The class itself and some members are exposed as they are needed for configuring FreeMarker.
+ *
+ * @see JavaScriptOrJSONCFormat
+ *
+ * @since 2.3.32
+ */
+public final class LegacyCFormat extends CFormat {
+ public static final LegacyCFormat INSTANCE = new LegacyCFormat();
+ public static final String NAME = "legacy";
+
+ /**
+ * "c" number format as it was before Incompatible Improvements 2.3.21.
+ */
+ static final DecimalFormat LEGACY_NUMBER_FORMAT_PROTOTYPE_2_3_0 = new DecimalFormat(
+ "0.################",
+ new DecimalFormatSymbols(Locale.US));
+ static {
+ LEGACY_NUMBER_FORMAT_PROTOTYPE_2_3_0.setGroupingUsed(false);
+ LEGACY_NUMBER_FORMAT_PROTOTYPE_2_3_0.setDecimalSeparatorAlwaysShown(false);
+ }
+
+ /**
+ * "c" number format as it was starting from Incompatible Improvements 2.3.21.
+ */
+ private static final DecimalFormat LEGACY_NUMBER_FORMAT_PROTOTYPE_2_3_21 = (DecimalFormat) LEGACY_NUMBER_FORMAT_PROTOTYPE_2_3_0.clone();
+ static {
+ DecimalFormatSymbols symbols = LEGACY_NUMBER_FORMAT_PROTOTYPE_2_3_21.getDecimalFormatSymbols();
+ symbols.setInfinity("INF");
+ symbols.setNaN("NaN");
+ LEGACY_NUMBER_FORMAT_PROTOTYPE_2_3_21.setDecimalFormatSymbols(symbols);
+ }
+
+ private LegacyCFormat() {
+ }
+
+ @Override
+ final String formatString(String s, Environment env) throws TemplateException {
+ return StringUtil.jsStringEnc(
+ s, StringUtil.JsStringEncCompatibility.JAVA_SCRIPT_OR_JSON, StringUtil.JsStringEncQuotation.QUOTATION_MARK);
+ }
+
+ @Override
+ final TemplateNumberFormat getTemplateNumberFormat(Environment env) {
+ return getTemplateNumberFormat(env.getConfiguration().getIncompatibleImprovements().intValue());
+ }
+
+ TemplateNumberFormat getTemplateNumberFormat(int iciVersion) {
+ return new LegacyCTemplateNumberFormat(getLegacyNumberFormat(iciVersion));
+ }
+
+ @Override
+ String getTrueString() {
+ return "true";
+ }
+
+ @Override
+ String getFalseString() {
+ return "false";
+ }
+
+ @Override
+ final String getNullString() {
+ return "null";
+ }
+
+ @Override
+ NumberFormat getLegacyNumberFormat(Environment env) {
+ // Note: DecimalFormat-s aren't thread-safe, so you must clone the static field value.
+ return getLegacyNumberFormat(env.getConfiguration().getIncompatibleImprovements().intValue());
+ }
+
+ NumberFormat getLegacyNumberFormat(int iciVersion) {
+ NumberFormat numberFormatPrototype;
+ if (iciVersion < _VersionInts.V_2_3_21) {
+ numberFormatPrototype = LEGACY_NUMBER_FORMAT_PROTOTYPE_2_3_0;
+ } else {
+ numberFormatPrototype = LEGACY_NUMBER_FORMAT_PROTOTYPE_2_3_21;
+ }
+ return (NumberFormat) numberFormatPrototype.clone();
+ }
+
+ @Override
+ public String getName() {
+ return NAME;
+ }
+
+ static final class LegacyCTemplateNumberFormat extends JavaTemplateNumberFormat {
+
+ public LegacyCTemplateNumberFormat(NumberFormat numberFormat) {
+ super(numberFormat, Environment.COMPUTER_FORMAT_STRING);
+ }
+
+ @Override
+ public String formatToPlainText(TemplateNumberModel numberModel) throws UnformattableValueException,
+ TemplateModelException {
+ Number number = TemplateFormatUtil.getNonNullNumber(numberModel);
+ return format(number);
+ }
+
+ @Override
+ public boolean isLocaleBound() {
+ return false;
+ }
+
+ @Override
+ String format(Number number) throws UnformattableValueException {
+ if (number instanceof Integer || number instanceof Long) {
+ // Accelerate these fairly common cases
+ return number.toString();
+ }
+ return super.format(number);
+ }
+
+ @Override
+ public String getDescription() {
+ return "LegacyC(" + super.getDescription() + ")";
+ }
+
+ }
+
+}
diff --git a/src/main/java/freemarker/core/XSCFormat.java b/src/main/java/freemarker/core/XSCFormat.java
index 016f8f27..49c4165b 100644
--- a/src/main/java/freemarker/core/XSCFormat.java
+++ b/src/main/java/freemarker/core/XSCFormat.java
@@ -47,7 +47,8 @@ public final class XSCFormat extends CFormat {
"INF", "-INF", "NaN",
"INF", "-INF", "NaN");
- private static final DecimalFormat LEGACY_NUMBER_FORMAT_PROTOTYPE = (DecimalFormat) Default230CFormat.LEGACY_NUMBER_FORMAT_PROTOTYPE.clone();
+ private static final DecimalFormat LEGACY_NUMBER_FORMAT_PROTOTYPE
+ = (DecimalFormat) LegacyCFormat.LEGACY_NUMBER_FORMAT_PROTOTYPE_2_3_0.clone();
static {
DecimalFormatSymbols symbols = LEGACY_NUMBER_FORMAT_PROTOTYPE.getDecimalFormatSymbols();
symbols.setInfinity("INF");
diff --git a/src/main/java/freemarker/core/_StandardCLanguages.java b/src/main/java/freemarker/core/_StandardCLanguages.java
index 9dec5a1b..9a22e7ca 100644
--- a/src/main/java/freemarker/core/_StandardCLanguages.java
+++ b/src/main/java/freemarker/core/_StandardCLanguages.java
@@ -33,8 +33,7 @@ final class StandardCFormats {
addStandardCFormat(JavaScriptCFormat.INSTANCE);
addStandardCFormat(JavaCFormat.INSTANCE);
addStandardCFormat(XSCFormat.INSTANCE);
- addStandardCFormat(Default230CFormat.INSTANCE);
- addStandardCFormat(Default2321CFormat.INSTANCE);
+ addStandardCFormat(LegacyCFormat.INSTANCE);
}
private static void addStandardCFormat(CFormat cFormat) {
diff --git a/src/main/java/freemarker/template/Configuration.java b/src/main/java/freemarker/template/Configuration.java
index 540294bd..7d4933c4 100644
--- a/src/main/java/freemarker/template/Configuration.java
+++ b/src/main/java/freemarker/template/Configuration.java
@@ -63,13 +63,12 @@ import freemarker.core.CFormat;
import freemarker.core.CSSOutputFormat;
import freemarker.core.CombinedMarkupOutputFormat;
import freemarker.core.Configurable;
-import freemarker.core.Default230CFormat;
-import freemarker.core.Default2321CFormat;
import freemarker.core.Environment;
import freemarker.core.HTMLOutputFormat;
import freemarker.core.JSONOutputFormat;
import freemarker.core.JavaScriptOrJSONCFormat;
import freemarker.core.JavaScriptOutputFormat;
+import freemarker.core.LegacyCFormat;
import freemarker.core.MarkupOutputFormat;
import freemarker.core.OutputFormat;
import freemarker.core.ParseException;
@@ -959,8 +958,7 @@ public class Configuration extends Configurable implements Cloneable, ParserConf
* {@code "computer"} {@link Configurable#setNumberFormat(String) number_format}) changes, if the
* {@link #setCFormat(CFormat) c_format} setting was left on its default. The default of
* {@link #setCFormat(CFormat) c_format} changes to {@link JavaScriptOrJSONCFormat#INSTANCE}, from
- * {@link Default2321CFormat#INSTANCE} (or from {@link Default230CFormat#INSTANCE}, depending on the
- * previous Incompatible Improvement value), and that's what contains the changes:</p>
+ * {@link LegacyCFormat#INSTANCE}, and that's what contains the changes:</p>
* <ul>
* <li><p>Changes affecting non-whole numbers, and whole numbers with over 100 digits:
* Formatting is now lossless, so it potentially shows much more decimals.
@@ -2512,13 +2510,9 @@ public class Configuration extends Configurable implements Cloneable, ParserConf
}
static CFormat getDefaultCFormat(Version incompatibleImprovements) {
- if (incompatibleImprovements.intValue() >= _VersionInts.V_2_3_32) {
- return JavaScriptOrJSONCFormat.INSTANCE;
- }
- if (incompatibleImprovements.intValue() >= _VersionInts.V_2_3_21) {
- return Default2321CFormat.INSTANCE;
- }
- return Default230CFormat.INSTANCE;
+ return incompatibleImprovements.intValue() >= _VersionInts.V_2_3_32
+ ? JavaScriptOrJSONCFormat.INSTANCE
+ : LegacyCFormat.INSTANCE;
}
/**
diff --git a/src/manual/en_US/book.xml b/src/manual/en_US/book.xml
index 06f82070..2f9d3b7d 100644
--- a/src/manual/en_US/book.xml
+++ b/src/manual/en_US/book.xml
@@ -6120,17 +6120,11 @@ To prove that "s" didn't contain the value in escaped form:
</listitem>
<listitem>
- <para><literal>"default 2.3.0"</literal>: Default for backward
- compatibility if the <link
+ <para><literal>"legacy"</literal>: Default for backward
+ compatibility when the <link
linkend="pgui_config_incompatible_improvements"><literal>incompatible_improvements</literal>
- setting</link> is less than 2.3.21. Avoid!</para>
- </listitem>
-
- <listitem>
- <para><literal>"default 2.3.21"</literal>: Default for backward
- compatibility if the <link
- linkend="pgui_config_incompatible_improvements"><literal>incompatible_improvements</literal>
- setting</link> is equal or greater than 2.3.21. Avoid!</para>
+ setting</link> is less than 2.3.32. Avoid! Can have rounding
+ losses, and formatting glitches for infinity and NaN.</para>
</listitem>
</itemizedlist>
@@ -13494,12 +13488,11 @@ GreEN mouse
<itemizedlist>
<listitem>
- <para><quote>JSON</quote>, <quote>default 2.3.0</quote>, and
- <quote>default 2.3.21</quote>: Gives a JSON string literal, that
- is, it will be surrounded with quotation marks
- (<literal>"</literal>), and will be escaped using backslash
- (<literal>\</literal>) where needed. For the exact escaping
- rules see <link linkend="ref_builtin_json_string">the
+ <para><quote>JSON</quote>, <quote>legacy</quote>: Gives a JSON
+ string literal, that is, it will be surrounded with quotation
+ marks (<literal>"</literal>), and will be escaped using
+ backslash (<literal>\</literal>) where needed. For the exact
+ escaping rules see <link linkend="ref_builtin_json_string">the
<literal>json_string</literal> built-in</link>.</para>
</listitem>
@@ -16036,18 +16029,18 @@ rif: foo XYr baar</programlisting>
<itemizedlist>
<listitem>
- <para>For all non-deprecated <literal>c_format</literal>-s
- that are built into FreeMarker: There's no rounding.</para>
+ <para>For all that are built into FreeMarker, except
+ <quote>legacy</quote> <literal>c_format </literal>: There's
+ no rounding.</para>
</listitem>
<listitem>
- <para>For the deprecated <literal>c_format</literal>-s,
- <quote>default 2.3.0</quote>, and <quote>default
- 2.3.21</quote>: The numbers are limited to 16 digits after
- the decimal dot, so rounding can occur. The these formats
- never use exponential form either, so the decimal point
- place is fixed. Thus, for example, 1E-17 will be formatted
- as <literal>0</literal>. </para>
+ <para>For the deprecated <literal>c_format</literal>,
+ <quote>legacy</quote>: The numbers are limited to 16 digits
+ after the decimal dot, so rounding can occur. The these
+ formats never use exponential form either, so the decimal
+ point place is fixed. Thus, for example, 1E-17 will be
+ formatted as <literal>0</literal>.</para>
</listitem>
</itemizedlist>
</listitem>
@@ -16079,14 +16072,19 @@ rif: foo XYr baar</programlisting>
<listitem>
<para>For <literal>c_format</literal> <quote>XS</quote>, and
- also for the deprecated <literal>c_format</literal>,
- <quote>default 2.3.21</quote>: <literal>INF</literal>,
- <literal>-INF</literal>, and <literal>NaN</literal>.</para>
+ also if <link
+ linkend="pgui_config_incompatible_improvements"><literal>incompatible_improvements</literal>
+ setting</link> is at least 2.3.21, for
+ <literal>c_format</literal>, <quote>legacy</quote>:
+ <literal>INF</literal>, <literal>-INF</literal>, and
+ <literal>NaN</literal>.</para>
</listitem>
<listitem>
- <para>For the deprecated <literal>c_format</literal>,
- <quote>default 2.3.0</quote>: Gives what
+ <para>For <literal>c_format</literal> <quote>legacy</quote>,
+ if <link
+ linkend="pgui_config_incompatible_improvements"><literal>incompatible_improvements</literal>
+ setting</link> is less than 2.3.21: Gives what
<literal>java.text.DecimalFormat</literal> does with US
locale, which are <literal>∞</literal>,
<literal>-∞</literal>, and <literal>�</literal> (U+FFFD,
@@ -16096,10 +16094,9 @@ rif: foo XYr baar</programlisting>
</listitem>
<listitem>
- <para>Exponential form is used by all non-deprecated
- <literal>c_format</literal>-s that are built into FreeMarker
- (but not by the deprecated <quote>default 2.3.0</quote>, and
- <quote>default 2.3.21</quote>):</para>
+ <para>Exponential form is used by all
+ <literal>c_format</literal>-s that are built into FreeMarker,
+ except <quote>legacy</quote>:</para>
<itemizedlist>
<listitem>
@@ -16231,8 +16228,8 @@ rif: foo XYr baar</programlisting>
<itemizedlist>
<listitem>
<para>For <quote>JSON</quote>, <quote>Java</quote>,
- <quote>JavaScript</quote>, <quote>default 2.3.0</quote>,
- <quote>default 2.3.21</quote>: <literal>null</literal></para>
+ <quote>JavaScript</quote>, and <quote>legacy</quote>:
+ <literal>null</literal></para>
</listitem>
<listitem>
@@ -30075,12 +30072,13 @@ TemplateModel x = env.getVariable("x"); // get variable x</programlisting>
<para>If you set the <link
linkend="pgui_config_incompatible_improvements_how_to_set"><literal>incompatible_improvements</literal>
setting</link> to 2.3.32, the default of
- <literal>c_format</literal> changes to
- <literal>JSON</literal>, which is a format that most targets
- can parse (because we just format simple values, not lists
- and maps). With lower
+ <literal>c_format</literal> changes from
+ <literal>"legacy"</literal> to <literal>"JavaScript or
+ JSON"</literal>, which is a format that most targets can
+ parse (because we just format simple values, not lists and
+ maps). With lower
<literal>incompatible_improvements</literal>, the default
- value is a <literal>c_format</literal> that emulates the old
+ value is <literal>"legacy"</literal> that emulates the old
behavior of <literal>?c</literal> (where you can lose
numerical prevision, etc.), so it's recommended to set it to
something else.</para>
diff --git a/src/test/java/freemarker/core/CustomCFormat.java b/src/test/java/freemarker/core/CustomCFormat.java
index 86658b0d..9ec224b8 100644
--- a/src/test/java/freemarker/core/CustomCFormat.java
+++ b/src/test/java/freemarker/core/CustomCFormat.java
@@ -36,8 +36,8 @@ class CustomCFormat extends CFormat {
"M:INF", "M:NINF", "M:NaN",
"M:INF", "M:NINF", "M:NaN");
- private static final DecimalFormat LEGACY_NUMBER_FORMAT_PROTOTYPE =
- (DecimalFormat) Default230CFormat.LEGACY_NUMBER_FORMAT_PROTOTYPE.clone();
+ private static final DecimalFormat LEGACY_NUMBER_FORMAT_PROTOTYPE
+ = (DecimalFormat) LegacyCFormat.LEGACY_NUMBER_FORMAT_PROTOTYPE_2_3_0.clone();
static {
DecimalFormatSymbols symbols = LEGACY_NUMBER_FORMAT_PROTOTYPE.getDecimalFormatSymbols();
diff --git a/src/test/java/freemarker/template/ConfigurationTest.java b/src/test/java/freemarker/template/ConfigurationTest.java
index 3a6dea5b..756b3fae 100644
--- a/src/test/java/freemarker/template/ConfigurationTest.java
+++ b/src/test/java/freemarker/template/ConfigurationTest.java
@@ -61,8 +61,6 @@ import freemarker.core.Configurable.SettingValueAssignmentException;
import freemarker.core.Configurable.UnknownSettingException;
import freemarker.core.ConfigurableTest;
import freemarker.core.CustomHTMLOutputFormat;
-import freemarker.core.Default230CFormat;
-import freemarker.core.Default2321CFormat;
import freemarker.core.DefaultTruncateBuiltinAlgorithm;
import freemarker.core.DummyOutputFormat;
import freemarker.core.Environment;
@@ -74,6 +72,7 @@ import freemarker.core.JSONCFormat;
import freemarker.core.JavaCFormat;
import freemarker.core.JavaScriptCFormat;
import freemarker.core.JavaScriptOrJSONCFormat;
+import freemarker.core.LegacyCFormat;
import freemarker.core.MarkupOutputFormat;
import freemarker.core.OptInTemplateClassResolver;
import freemarker.core.OutputFormat;
@@ -190,13 +189,13 @@ public class ConfigurationTest extends TestCase {
assertFalse(((DefaultObjectWrapper) cfg.getObjectWrapper()).getPreferIndexedReadMethod());
cfg = new Configuration(Configuration.VERSION_2_3_0);
- assertSame(Default230CFormat.INSTANCE, cfg.getCFormat());
+ assertSame(LegacyCFormat.INSTANCE, cfg.getCFormat());
cfg.setIncompatibleImprovements(Configuration.VERSION_2_3_20);
- assertSame(Default230CFormat.INSTANCE, cfg.getCFormat());
+ assertSame(LegacyCFormat.INSTANCE, cfg.getCFormat());
cfg.setIncompatibleImprovements(Configuration.VERSION_2_3_21);
- assertSame(Default2321CFormat.INSTANCE, cfg.getCFormat());
+ assertSame(LegacyCFormat.INSTANCE, cfg.getCFormat());
cfg.setIncompatibleImprovements(Configuration.VERSION_2_3_31);
- assertSame(Default2321CFormat.INSTANCE, cfg.getCFormat());
+ assertSame(LegacyCFormat.INSTANCE, cfg.getCFormat());
cfg.setIncompatibleImprovements(Configuration.VERSION_2_3_32);
assertSame(JavaScriptOrJSONCFormat.INSTANCE, cfg.getCFormat());
cfg.setCFormat(JavaScriptOrJSONCFormat.INSTANCE); // Same as default, but explicitly set now
@@ -1921,17 +1920,17 @@ public class ConfigurationTest extends TestCase {
public void testCFormat() throws TemplateException {
Configuration cfg = new Configuration(Configuration.VERSION_2_3_21);
- assertSame(Default2321CFormat.INSTANCE, cfg.getCFormat());
- cfg.setSetting(Configuration.C_FORMAT_KEY_SNAKE_CASE, Default230CFormat.NAME);
- assertSame(Default230CFormat.INSTANCE, cfg.getCFormat());
+ assertSame(LegacyCFormat.INSTANCE, cfg.getCFormat());
+ cfg.setSetting(Configuration.C_FORMAT_KEY_SNAKE_CASE, LegacyCFormat.NAME);
+ assertSame(LegacyCFormat.INSTANCE, cfg.getCFormat());
cfg.setSetting(Configuration.C_FORMAT_KEY_CAMEL_CASE, JSONCFormat.NAME);
assertSame(JSONCFormat.INSTANCE, cfg.getCFormat());
cfg.setSetting(Configuration.C_FORMAT_KEY_CAMEL_CASE, "default");
- cfg.setSetting(Configuration.C_FORMAT_KEY_SNAKE_CASE, Default2321CFormat.NAME);
+ cfg.setSetting(Configuration.C_FORMAT_KEY_SNAKE_CASE, LegacyCFormat.NAME);
for (CFormat standardCFormat : new CFormat[] {
- Default230CFormat.INSTANCE, Default2321CFormat.INSTANCE,
+ LegacyCFormat.INSTANCE,
JSONCFormat.INSTANCE, JavaScriptCFormat.INSTANCE, JavaCFormat.INSTANCE,
XSCFormat.INSTANCE
}) {