Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8323699

MessageFormat.toPattern() generates non-equivalent MessageFormat pattern

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P4 P4
    • 23
    • 8, 11, 17, 21
    • core-libs
    • b09
    • generic
    • generic
    • Verified

      Under the assumption that the intention of MessageFormat.toPattern() is to generate a pattern that can be later used to recreate the same `MessageFormat`, then there is a case where MessageFormat.toPattern() is generates the wrong pattern string.

      The bug is that MessageFormat.toPattern()` (correctly) quotes plain text opening "{" brace characters in the pattern, it does not quote plain text closing "}" brace characters. This is a problem because the pattern parser interprets a closing "}" brace character as the end of a nested format string.

      As a result, when going from MessageFormat -> Pattern String -> MessageFormat, it's possible for the format to change semantically. This is obviously a problem for (for example) tools that store and retrieve MessageFormat's as pattern strings for the purpose of i18n, etc.

      Test case:

      import java.text.MessageFormat;

      public class MessageFormatBug {

          public static void main(String[] args) {

              String pattern1 = "{0,choice,0.0#option A: {1}|1.0#option B: {1}'}'}";
              MessageFormat format1 = new MessageFormat(pattern1);
              String result1 = format1.format(new Object[] { 0, 5 });

              String pattern2 = format1.toPattern();
              MessageFormat format2 = new MessageFormat(pattern2);
              String result2 = format2.format(new Object[] { 0, 5 });

              System.out.println(String.format("pattern1 = \"%s\"", pattern1));
              System.out.println(String.format("pattern2 = \"%s\"", pattern2));
              System.out.println(String.format("result1 = \"%s\"", result1));
              System.out.println(String.format("result2 = \"%s\"", result2));
              System.out.println("results are equal = " + result1.equals(result2));
          }
      }

      Expected output:

      pattern1 = "{0,choice,0.0#option A: {1}|1.0#option B: {1}'}'}"
      pattern2 = "{0,choice,0.0#option A: {1}|1.0#option B: {1}'}'}"
      result1 = "option A: 5"
      result2 = "option A: 5"
      results are equal = true

      Actual output:

      pattern1 = "{0,choice,0.0#option A: {1}|1.0#option B: {1}'}'}"
      pattern2 = "{0,choice,0.0#option A: {1}|1.0#option B: {1}}}"
      result1 = "option A: 5"
      result2 = "option A: 5}"
      results are equal = false

      Reproducible in JDK 8, 11, 17, and 21.

            acobbs Archie Cobbs
            acobbs Archie Cobbs
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated:
              Resolved: