6230751: [Fmt-Ch] Recursive MessageFormats in ChoiceFormats ignore indicated subformats

Reviewed-by: naoto
This commit is contained in:
Justin Lu 2023-12-12 19:25:20 +00:00
parent a3447ec656
commit aadf36809c
2 changed files with 36 additions and 57 deletions

View file

@ -88,7 +88,6 @@ import java.util.Arrays;
* <p> * <p>
* Below is an example of constructing a ChoiceFormat with arrays to format * Below is an example of constructing a ChoiceFormat with arrays to format
* and parse values: * and parse values:
* <blockquote>
* {@snippet lang=java : * {@snippet lang=java :
* double[] limits = {1,2,3,4,5,6,7}; * double[] limits = {1,2,3,4,5,6,7};
* String[] dayOfWeekNames = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"}; * String[] dayOfWeekNames = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"};
@ -100,34 +99,27 @@ import java.util.Arrays;
* + form.parse(form.format(i),status)); * + form.parse(form.format(i),status));
* } * }
* } * }
* </blockquote> *
* <p>
* For more sophisticated patterns, {@code ChoiceFormat} can be used with * For more sophisticated patterns, {@code ChoiceFormat} can be used with
* {@link MessageFormat} to produce accurate forms for singular and plural: * {@link MessageFormat} to produce accurate forms for singular and plural:
* <blockquote>
* {@snippet lang=java : * {@snippet lang=java :
* double[] filelimits = {0,1,2}; * MessageFormat msgFmt = new MessageFormat("The disk \"{0}\" contains {1}.");
* String[] filepart = {"are no files","is one file","are {2} files"}; * double[] fileLimits = {0,1,2};
* ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart); * String[] filePart = {"no files","one file","{1,number} files"};
* Format[] testFormats = {fileform, null, NumberFormat.getInstance()}; * ChoiceFormat fileChoices = new ChoiceFormat(fileLimits, filePart);
* MessageFormat pattform = new MessageFormat("There {0} on {1}"); * msgFmt.setFormatByArgumentIndex(1, fileChoices);
* pattform.setFormats(testFormats); * Object[] args = {"MyDisk", 1273};
* Object[] testArgs = {null, "ADisk", null}; * System.out.println(msgFmt.format(args));
* for (int i = 0; i < 4; ++i) {
* testArgs[0] = Integer.valueOf(i);
* testArgs[2] = testArgs[0];
* System.out.println(pattform.format(testArgs));
* } * }
* } * The output with different values for {@code fileCount}:
* </blockquote> * <blockquote><pre>
* Would output the following: * The disk "MyDisk" contains no files.
* <blockquote> * The disk "MyDisk" contains one file.
* <pre>{@code * The disk "MyDisk" contains 1,273 files.
* There are no files on ADisk * </pre></blockquote>
* There is one file on ADisk * See {@link MessageFormat##pattern_caveats MessageFormat} for caveats regarding
* There are 2 files on ADisk * {@code MessageFormat} patterns within a {@code ChoiceFormat} pattern.
* There are 3 files on ADisk
* }</pre>
* </blockquote>
* *
* <h2><a id="patterns">Patterns</a></h2> * <h2><a id="patterns">Patterns</a></h2>
* A {@code ChoiceFormat} pattern has the following syntax: * A {@code ChoiceFormat} pattern has the following syntax:
@ -194,7 +186,6 @@ import java.util.Arrays;
* {@code new ChoiceFormat("1# ''one'' ").format(1)} returns {@code " 'one' "}. * {@code new ChoiceFormat("1# ''one'' ").format(1)} returns {@code " 'one' "}.
* *
* <p>Below is an example of constructing a ChoiceFormat with a pattern: * <p>Below is an example of constructing a ChoiceFormat with a pattern:
* <blockquote>
* {@snippet lang=java : * {@snippet lang=java :
* ChoiceFormat fmt = new ChoiceFormat( * ChoiceFormat fmt = new ChoiceFormat(
* "-1#is negative| 0#is zero or fraction | 1#is one |1.0<is 1+ |2#is two |2<is more than 2."); * "-1#is negative| 0#is zero or fraction | 1#is one |1.0<is 1+ |2#is two |2<is more than 2.");
@ -210,7 +201,6 @@ import java.util.Arrays;
* System.out.println(fmt.format(Double.NaN)); // outputs "is negative" * System.out.println(fmt.format(Double.NaN)); // outputs "is negative"
* System.out.println(fmt.format(Double.POSITIVE_INFINITY)); // outputs "is more than 2." * System.out.println(fmt.format(Double.POSITIVE_INFINITY)); // outputs "is more than 2."
* } * }
* </blockquote>
* *
* <h2><a id="synchronization">Synchronization</a></h2> * <h2><a id="synchronization">Synchronization</a></h2>
* *

View file

@ -231,7 +231,6 @@ import java.util.Objects;
* <p> * <p>
* The first example uses the static method {@code MessageFormat.format}, * The first example uses the static method {@code MessageFormat.format},
* which internally creates a {@code MessageFormat} for one-time use: * which internally creates a {@code MessageFormat} for one-time use:
* <blockquote>
* {@snippet lang=java : * {@snippet lang=java :
* int planet = 7; * int planet = 7;
* String event = "a disturbance in the Force"; * String event = "a disturbance in the Force";
@ -240,7 +239,6 @@ import java.util.Objects;
* "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.", * "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
* planet, new Date(), event); * planet, new Date(), event);
* } * }
* </blockquote>
* The output is: * The output is:
* <blockquote><pre> * <blockquote><pre>
* At 12:30 PM on Jul 3, 2053, there was a disturbance in the Force on planet 7. * At 12:30 PM on Jul 3, 2053, there was a disturbance in the Force on planet 7.
@ -249,7 +247,6 @@ import java.util.Objects;
* <p> * <p>
* The following example creates a {@code MessageFormat} instance that * The following example creates a {@code MessageFormat} instance that
* can be used repeatedly: * can be used repeatedly:
* <blockquote>
* {@snippet lang=java : * {@snippet lang=java :
* int fileCount = 1273; * int fileCount = 1273;
* String diskName = "MyDisk"; * String diskName = "MyDisk";
@ -260,7 +257,6 @@ import java.util.Objects;
* *
* System.out.println(form.format(testArgs)); * System.out.println(form.format(testArgs));
* } * }
* </blockquote>
* The output with different values for {@code fileCount}: * The output with different values for {@code fileCount}:
* <blockquote><pre> * <blockquote><pre>
* The disk "MyDisk" contains 0 file(s). * The disk "MyDisk" contains 0 file(s).
@ -269,23 +265,17 @@ import java.util.Objects;
* </pre></blockquote> * </pre></blockquote>
* *
* <p> * <p>
* For more sophisticated patterns, you can use a {@code ChoiceFormat} * For more sophisticated patterns, {@link ChoiceFormat} can be used with
* to produce correct forms for singular and plural: * {@code MessageFormat} to produce accurate forms for singular and plural:
* <blockquote>
* {@snippet lang=java : * {@snippet lang=java :
* MessageFormat form = new MessageFormat("The disk \"{1}\" contains {0}."); * MessageFormat msgFmt = new MessageFormat("The disk \"{0}\" contains {1}.");
* double[] filelimits = {0,1,2}; * double[] fileLimits = {0,1,2};
* String[] filepart = {"no files","one file","{0,number} files"}; * String[] filePart = {"no files","one file","{1,number} files"};
* ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart); * ChoiceFormat fileChoices = new ChoiceFormat(fileLimits, filePart);
* form.setFormatByArgumentIndex(0, fileform); * msgFmt.setFormatByArgumentIndex(1, fileChoices);
* * Object[] args = {"MyDisk", 1273};
* int fileCount = 1273; * System.out.println(msgFmt.format(args));
* String diskName = "MyDisk";
* Object[] testArgs = {Long.valueOf(fileCount), diskName};
*
* System.out.println(form.format(testArgs));
* } * }
* </blockquote>
* The output with different values for {@code fileCount}: * The output with different values for {@code fileCount}:
* <blockquote><pre> * <blockquote><pre>
* The disk "MyDisk" contains no files. * The disk "MyDisk" contains no files.
@ -297,24 +287,26 @@ import java.util.Objects;
* You can create the {@code ChoiceFormat} programmatically, as in the * You can create the {@code ChoiceFormat} programmatically, as in the
* above example, or by using a pattern. See {@link ChoiceFormat} * above example, or by using a pattern. See {@link ChoiceFormat}
* for more information. * for more information.
* <blockquote>
* {@snippet lang=java : * {@snippet lang=java :
* form.applyPattern( * msgFmt.applyPattern(
* "There {0,choice,0#are no files|1#is one file|1<are {0,number,integer} files}."); * "There {0,choice,0#are no files|1#is one file|1<are {1,number,integer} files}.");
* } * }
* </blockquote>
* *
* <p> * <p>
* <strong>Note:</strong> As we see above, the string produced * <strong id="pattern_caveats">Notes:</strong> As seen in the previous snippet,
* by a {@code ChoiceFormat} in {@code MessageFormat} is treated as special; * the string produced by a {@code ChoiceFormat} in {@code MessageFormat} is
* occurrences of '{' are used to indicate subformats, and cause recursion. * treated as special; occurrences of '{' are used to indicate subformats, and
* cause recursion. If a {@code FormatElement} is defined in the {@code ChoiceFormat}
* pattern, it will only be formatted according to the {@code FormatType} and
* {@code FormatStyle} pattern provided. The associated subformats of the
* top level {@code MessageFormat} will not be applied to the {@code FormatElement}
* defined in the {@code ChoiceFormat} pattern.
* If you create both a {@code MessageFormat} and {@code ChoiceFormat} * If you create both a {@code MessageFormat} and {@code ChoiceFormat}
* programmatically (instead of using the string patterns), then be careful not to * programmatically (instead of using the string patterns), then be careful not to
* produce a format that recurses on itself, which will cause an infinite loop. * produce a format that recurses on itself, which will cause an infinite loop.
* <p> * <p>
* When a single argument is parsed more than once in the string, the last match * When a single argument is parsed more than once in the string, the last match
* will be the final result of the parsing. For example, * will be the final result of the parsing. For example,
* <blockquote>
* {@snippet lang=java : * {@snippet lang=java :
* MessageFormat mf = new MessageFormat("{0,number,#.##}, {0,number,#.#}"); * MessageFormat mf = new MessageFormat("{0,number,#.##}, {0,number,#.#}");
* Object[] objs = {Double.valueOf(3.1415)}; * Object[] objs = {Double.valueOf(3.1415)};
@ -323,20 +315,17 @@ import java.util.Objects;
* objs = mf.parse(result, new ParsePosition(0)); * objs = mf.parse(result, new ParsePosition(0));
* // objs now equals {Double.valueOf(3.1)} * // objs now equals {Double.valueOf(3.1)}
* } * }
* </blockquote>
* *
* <p> * <p>
* Likewise, parsing with a {@code MessageFormat} object using patterns containing * Likewise, parsing with a {@code MessageFormat} object using patterns containing
* multiple occurrences of the same argument would return the last match. For * multiple occurrences of the same argument would return the last match. For
* example, * example,
* <blockquote>
* {@snippet lang=java : * {@snippet lang=java :
* MessageFormat mf = new MessageFormat("{0}, {0}, {0}"); * MessageFormat mf = new MessageFormat("{0}, {0}, {0}");
* String forParsing = "x, y, z"; * String forParsing = "x, y, z";
* Object[] objs = mf.parse(forParsing, new ParsePosition(0)); * Object[] objs = mf.parse(forParsing, new ParsePosition(0));
* // objs now equals {new String("z")} * // objs now equals {new String("z")}
* } * }
* </blockquote>
* *
* <h3><a id="synchronization">Synchronization</a></h3> * <h3><a id="synchronization">Synchronization</a></h3>
* *