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 2015/09/18 22:21:55 UTC

incubator-freemarker git commit: @@ can't be used to escape @ at the beginning of format strings anymore, because it was confusing on Android, where DecimalFormat supports patterns like "@@@@@@". If a pattern has to output a literal @ as the first charac

Repository: incubator-freemarker
Updated Branches:
  refs/heads/2.3-gae d5bfedbad -> 8e7c80a43


@@ can't be used to escape @ at the beginning of format strings anymore, because it was confusing on Android, where DecimalFormat supports patterns like "@@@@@@". If a pattern has to output a literal @ as the first character, you can simply use quoting as defined by DecimalFormat and SimpleDateFormat (for example, "'@'0.##").


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/8e7c80a4
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/8e7c80a4
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/8e7c80a4

Branch: refs/heads/2.3-gae
Commit: 8e7c80a439273ea81a660611b4fa4a807b6c4e6f
Parents: d5bfedb
Author: ddekany <dd...@apache.org>
Authored: Fri Sep 18 22:20:21 2015 +0200
Committer: ddekany <dd...@apache.org>
Committed: Fri Sep 18 22:21:31 2015 +0200

----------------------------------------------------------------------
 src/main/java/freemarker/core/Configurable.java | 14 +++++++---
 src/main/java/freemarker/core/Environment.java  | 28 ++++---------------
 src/manual/book.xml                             | 29 ++++++++++++++------
 .../java/freemarker/core/DateFormatTest.java    | 18 ++++++++----
 .../java/freemarker/core/NumberFormatTest.java  | 18 ++++++++----
 5 files changed, 60 insertions(+), 47 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8e7c80a4/src/main/java/freemarker/core/Configurable.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/Configurable.java b/src/main/java/freemarker/core/Configurable.java
index bdc76ae..4ad0a2e 100644
--- a/src/main/java/freemarker/core/Configurable.java
+++ b/src/main/java/freemarker/core/Configurable.java
@@ -778,7 +778,8 @@ public class Configurable {
      * meaning).
      * 
      * @param customNumberFormats
-     *            Can't be {@code null}.
+     *            Can't be {@code null}. The name must start with an UNICODE letter, and can only contain UNICODE
+     *            letters and digits.
      * 
      * @since 2.3.24
      */
@@ -793,12 +794,16 @@ public class Configurable {
             if (name.length() == 0) {
                 throw new IllegalArgumentException("Format names can't be 0 length");
             }
-            if (name.charAt(0) == '@') {
+            char firstChar = name.charAt(0);
+            if (firstChar == '@') {
                 throw new IllegalArgumentException(
                         "Format names can't start with '@'. '@' is only used when referring to them from format "
                         + "strings. In: " + name);
             }
-            for (int i = 0; i < name.length(); i++) {
+            if (!Character.isLetter(firstChar)) {
+                throw new IllegalArgumentException("Format name must start with letter: " + name);
+            }
+            for (int i = 1; i < name.length(); i++) {
                 // Note that we deliberately don't allow "_" here.
                 if (!Character.isLetterOrDigit(name.charAt(i))) {
                     throw new IllegalArgumentException("Format name can only contain letters and digits: " + name);
@@ -1149,7 +1154,8 @@ public class Configurable {
      * meaning).
      *
      * @param customDateFormats
-     *            Can't be {@code null}.
+     *            Can't be {@code null}. The name must start with an UNICODE letter, and can only contain UNICODE
+     *            letters and digits.
      * 
      * @since 2.3.24
      */

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8e7c80a4/src/main/java/freemarker/core/Environment.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/Environment.java b/src/main/java/freemarker/core/Environment.java
index 96e31fd..1e6aa73 100644
--- a/src/main/java/freemarker/core/Environment.java
+++ b/src/main/java/freemarker/core/Environment.java
@@ -1235,8 +1235,8 @@ public final class Environment extends Configurable {
         int formatStringLen = formatString.length();
         if (formatStringLen > 1
                 && formatString.charAt(0) == '@'
-                && formatString.charAt(1) != '@'
-                && (isIcI2324OrLater() || hasCustomFormats())) {
+                && (isIcI2324OrLater() || hasCustomFormats())
+                && Character.isLetter(formatString.charAt(1))) {
             final String name;
             final String params;
             {
@@ -1259,13 +1259,6 @@ public final class Environment extends Configurable {
 
             return formatFactory.get(params, locale, this);
         } else {
-            if (formatStringLen > 1
-                    && formatString.charAt(0) == '@'
-                    && formatString.charAt(1) == '@'
-                    && (isIcI2324OrLater() || hasCustomFormats())) {
-                // Unescape @ escaped as @@
-                formatString = formatString.substring(1);
-            }
             return JavaTemplateNumberFormatFactory.INSTANCE.get(formatString, locale, this);
         }
     }
@@ -1742,8 +1735,8 @@ public final class Environment extends Configurable {
             formatParams = formatString; // for speed, we don't remove the prefix
         } else if (firstChar == '@'
                 && formatStringLen > 1
-                && formatString.charAt(1) != '@'
-                && (isIcI2324OrLater() || hasCustomFormats())) {
+                && (isIcI2324OrLater() || hasCustomFormats())
+                && Character.isLetter(formatString.charAt(1))) {
             final String name;
             {
                 int endIdx;
@@ -1763,19 +1756,8 @@ public final class Environment extends Configurable {
                         "No custom date format was defined with name " + StringUtil.jQuote(name));
             }
         } else {
-            String unescapedFormatString;
-            if (firstChar == '@'
-                    && formatStringLen > 1
-                    && formatString.charAt(1) == '@'
-                    && (isIcI2324OrLater() || hasCustomFormats())) {
-                // Unescape @ escaped as @@
-                unescapedFormatString = formatString.substring(1);
-            } else {
-                unescapedFormatString = formatString;
-            }
-
+            formatParams = formatString;
             formatFactory = JavaTemplateDateFormatFactory.INSTANCE;
-            formatParams = unescapedFormatString;
         }
 
         return formatFactory.get(formatParams, dateType, locale, timeZone,

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8e7c80a4/src/manual/book.xml
----------------------------------------------------------------------
diff --git a/src/manual/book.xml b/src/manual/book.xml
index af492e4..0506f18 100644
--- a/src/manual/book.xml
+++ b/src/manual/book.xml
@@ -25756,10 +25756,10 @@ TemplateModel x = env.getVariable("x");  // get variable x</programlisting>
               or <literal>${n?string.@foo}</literal>,
               <literal>${n?string.@foo_params}</literal>. For backward
               compatibility, the initial <literal>@</literal> only has this
-              special meaning if you have any custom formats or <link
+              special meaning if either you have any custom formats or <link
               linkend="pgui_config_incompatible_improvements">the
               <literal>incompatible_improvements</literal> setting</link> is
-              2.3.24 or higher.</para>
+              at lest 2.3.24.</para>
             </listitem>
 
             <listitem>
@@ -25915,12 +25915,12 @@ TemplateModel x = env.getVariable("x");  // get variable x</programlisting>
                   Like, you can do <literal>cfg.setNumberFormat("@foo
                   params")</literal>, or <literal>&lt;#setting
                   number_format='@foo params'&gt;</literal>, or
-                  <literal>${n?string.@foo_params}</literal>. Note that an
-                  <replaceable>initial</replaceable> <literal>@</literal> in
-                  format strings is reserved for this purpose with
-                  <literal>incompatible_improvements</literal> to 2.3.24, and
-                  need to be escaped as <literal>@@</literal> if it has to be
-                  there literally. Note that the
+                  <literal>${n?string.@foo_params}</literal>. For backward
+                  compatibility, the initial <literal>@</literal> only has
+                  this special meaning if either you have any custom formats
+                  or <link linkend="pgui_config_incompatible_improvements">the
+                  <literal>incompatible_improvements</literal> setting</link>
+                  is at least 2.3.24. Note that the
                   <literal>custom_number_formats</literal> and
                   <literal>custom_date_formats</literal> settings can be set
                   per-template (via the new
@@ -26160,6 +26160,19 @@ TemplateModel x = env.getVariable("x");  // get variable x</programlisting>
             </listitem>
 
             <listitem>
+              <para><literal>@@</literal> can't be used to escape
+              <literal>@</literal> at the beginning of format strings anymore,
+              because it was confusing on Android, where
+              <literal>DecimalFormat</literal> supports patterns like
+              <literal>"@@@@@@"</literal>. If a pattern has to output a
+              literal <literal>@</literal> as the first character, you can
+              simply use quoting as defined by
+              <literal>DecimalFormat</literal> and
+              <literal>SimpleDateFormat</literal> (for example,
+              <literal>"'@'0.##"</literal>).</para>
+            </listitem>
+
+            <listitem>
               <para><literal>?date</literal>, <literal>?time</literal> and
               <literal>?datetime</literal> now can be called as 0 argument
               method, like <literal>?date()</literal>, etc., which returns the

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8e7c80a4/src/test/java/freemarker/core/DateFormatTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/DateFormatTest.java b/src/test/java/freemarker/core/DateFormatTest.java
index 741e68b..c21b83a 100644
--- a/src/test/java/freemarker/core/DateFormatTest.java
+++ b/src/test/java/freemarker/core/DateFormatTest.java
@@ -205,23 +205,29 @@ public class DateFormatTest extends TemplateTest {
         
         cfg.setCustomDateFormats(Collections.<String, TemplateDateFormatFactory>emptyMap());
         
-        cfg.setDateTimeFormat("@@yyyy");
-        assertOutput("${d}", "@@1970");
         cfg.setDateTimeFormat("@epoch");
         assertErrorContains("${d}", "\"@epoch\"");
+        cfg.setDateTimeFormat("'@'yyyy");
+        assertOutput("${d}", "@1970");
+        cfg.setDateTimeFormat("@@yyyy");
+        assertOutput("${d}", "@@1970");
         
         cfg.setIncompatibleImprovements(Configuration.VERSION_2_3_24);
-        cfg.setDateTimeFormat("@@yyyy");
-        assertOutput("${d}", "@1970");
         cfg.setDateTimeFormat("@epoch");
         assertErrorContains("${d}", "custom", "\"epoch\"");
+        cfg.setDateTimeFormat("'@'yyyy");
+        assertOutput("${d}", "@1970");
+        cfg.setDateTimeFormat("@@yyyy");
+        assertOutput("${d}", "@@1970");
     }
 
     protected void testIcIAndEscapingWhenCustFormsAreAccepted(Configuration cfg) throws IOException, TemplateException {
-        cfg.setDateTimeFormat("@@yyyy");
-        assertOutput("${d}", "@1970");
         cfg.setDateTimeFormat("@epoch");
         assertOutput("${d}", "12345678");
+        cfg.setDateTimeFormat("'@'yyyy");
+        assertOutput("${d}", "@1970");
+        cfg.setDateTimeFormat("@@yyyy");
+        assertOutput("${d}", "@@1970");
     }
     
     @Test

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8e7c80a4/src/test/java/freemarker/core/NumberFormatTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/NumberFormatTest.java b/src/test/java/freemarker/core/NumberFormatTest.java
index 78b420f..b30b72a 100644
--- a/src/test/java/freemarker/core/NumberFormatTest.java
+++ b/src/test/java/freemarker/core/NumberFormatTest.java
@@ -215,23 +215,29 @@ public class NumberFormatTest extends TemplateTest {
         testIcIAndEscapingWhenCustFormsAccepted(cfg);
         
         cfg.setCustomNumberFormats(Collections.<String, TemplateNumberFormatFactory>emptyMap());
-        cfg.setNumberFormat("@@0");
-        assertOutput("${10}", "@@10");
         cfg.setNumberFormat("@hex");
         assertOutput("${10}", "@hex10");
+        cfg.setNumberFormat("'@'0");
+        assertOutput("${10}", "@10");
+        cfg.setNumberFormat("@@0");
+        assertOutput("${10}", "@@10");
         
         cfg.setIncompatibleImprovements(Configuration.VERSION_2_3_24);
-        cfg.setNumberFormat("@@0");
-        assertOutput("${10}", "@10");
         cfg.setNumberFormat("@hex");
         assertErrorContains("${10}", "custom", "\"hex\"");
+        cfg.setNumberFormat("'@'0");
+        assertOutput("${10}", "@10");
+        cfg.setNumberFormat("@@0");
+        assertOutput("${10}", "@@10");
     }
 
     protected void testIcIAndEscapingWhenCustFormsAccepted(Configuration cfg) throws IOException, TemplateException {
-        cfg.setNumberFormat("@@0");
-        assertOutput("${10}", "@10");
         cfg.setNumberFormat("@hex");
         assertOutput("${10}", "a");
+        cfg.setNumberFormat("'@'0");
+        assertOutput("${10}", "@10");
+        cfg.setNumberFormat("@@0");
+        assertOutput("${10}", "@@10");
     }
 
     @Test