# HG changeset patch
# User naoto
# Date 1553272296 25200
# Node ID 83deaa8f0c8ef4e611312494aef7c8955554e380
# Parent 51195881bd3a3b2cb190379a2a7656c3eb51ebf5
8220224: With CLDR provider, NumberFormat.format could not handle locale with number extension correctly.
Reviewed-by: darcy
diff -r 51195881bd3a -r 83deaa8f0c8e src/java.base/share/classes/java/text/CompactNumberFormat.java
--- a/src/java.base/share/classes/java/text/CompactNumberFormat.java Fri Mar 22 08:18:26 2019 -0700
+++ b/src/java.base/share/classes/java/text/CompactNumberFormat.java Fri Mar 22 09:31:36 2019 -0700
@@ -836,7 +836,8 @@
if (ch == QUOTE) {
ch = pattern.charAt(index++);
if (ch == MINUS_SIGN) {
- ch = symbols.getMinusSign();
+ sb.append(symbols.getMinusSignText());
+ continue;
}
}
sb.append(ch);
@@ -859,11 +860,14 @@
if (ch == QUOTE) {
ch = pattern.charAt(index++);
if (ch == MINUS_SIGN) {
- ch = symbols.getMinusSign();
+ String minusText = symbols.getMinusSignText();
FieldPosition fp = new FieldPosition(NumberFormat.Field.SIGN);
fp.setBeginIndex(stringIndex);
- fp.setEndIndex(stringIndex + 1);
+ fp.setEndIndex(stringIndex + minusText.length());
positions.add(fp);
+ stringIndex += minusText.length();
+ affix.append(minusText);
+ continue;
}
}
stringIndex++;
diff -r 51195881bd3a -r 83deaa8f0c8e src/java.base/share/classes/java/text/DecimalFormat.java
--- a/src/java.base/share/classes/java/text/DecimalFormat.java Fri Mar 22 08:18:26 2019 -0700
+++ b/src/java.base/share/classes/java/text/DecimalFormat.java Fri Mar 22 09:31:36 2019 -0700
@@ -54,20 +54,20 @@
import sun.util.locale.provider.ResourceBundleBasedAdapter;
/**
- * DecimalFormat
is a concrete subclass of
- * NumberFormat
that formats decimal numbers. It has a variety of
+ * {@code DecimalFormat} is a concrete subclass of
+ * {@code NumberFormat} that formats decimal numbers. It has a variety of
* features designed to make it possible to parse and format numbers in any
* locale, including support for Western, Arabic, and Indic digits. It also
* supports different kinds of numbers, including integers (123), fixed-point
* numbers (123.4), scientific notation (1.23E4), percentages (12%), and
* currency amounts ($123). All of these can be localized.
*
- *
To obtain a NumberFormat
for a specific locale, including the
- * default locale, call one of NumberFormat
's factory methods, such
- * as getInstance()
. In general, do not call the
- * DecimalFormat
constructors directly, since the
- * NumberFormat
factory methods may return subclasses other than
- * DecimalFormat
. If you need to customize the format object, do
+ *
To obtain a {@code NumberFormat} for a specific locale, including the + * default locale, call one of {@code NumberFormat}'s factory methods, such + * as {@code getInstance()}. In general, do not call the + * {@code DecimalFormat} constructors directly, since the + * {@code NumberFormat} factory methods may return subclasses other than + * {@code DecimalFormat}. If you need to customize the format object, do * something like this: * *
* - *@@ -77,16 +77,16 @@ * } *
A DecimalFormat
comprises a pattern and a set of
+ *
A {@code DecimalFormat} comprises a pattern and a set of
* symbols. The pattern may be set directly using
- * applyPattern()
, or indirectly using the API methods. The
- * symbols are stored in a DecimalFormatSymbols
object. When using
- * the NumberFormat
factory methods, the pattern and symbols are
- * read from localized ResourceBundle
s.
+ * {@code applyPattern()}, or indirectly using the API methods. The
+ * symbols are stored in a {@code DecimalFormatSymbols} object. When using
+ * the {@code NumberFormat} factory methods, the pattern and symbols are
+ * read from localized {@code ResourceBundle}s.
*
*
DecimalFormat
patterns have the following syntax:
+ * {@code DecimalFormat} patterns have the following syntax:
* * - ** Pattern: * PositivePattern @@ -123,26 +123,26 @@ * 0 MinimumExponentopt *
A DecimalFormat
pattern contains a positive and negative
- * subpattern, for example, "#,##0.00;(#,##0.00)"
. Each
+ *
A {@code DecimalFormat} pattern contains a positive and negative
+ * subpattern, for example, {@code "#,##0.00;(#,##0.00)"}. Each
* subpattern has a prefix, numeric part, and suffix. The negative subpattern
* is optional; if absent, then the positive subpattern prefixed with the
- * localized minus sign ('-'
in most locales) is used as the
- * negative subpattern. That is, "0.00"
alone is equivalent to
- * "0.00;-0.00"
. If there is an explicit negative subpattern, it
+ * localized minus sign ({@code '-'} in most locales) is used as the
+ * negative subpattern. That is, {@code "0.00"} alone is equivalent to
+ * {@code "0.00;-0.00"}. If there is an explicit negative subpattern, it
* serves only to specify the negative prefix and suffix; the number of digits,
* minimal digits, and other characteristics are all the same as the positive
- * pattern. That means that "#,##0.0#;(#)"
produces precisely
- * the same behavior as "#,##0.0#;(#,##0.0#)"
.
+ * pattern. That means that {@code "#,##0.0#;(#)"} produces precisely
+ * the same behavior as {@code "#,##0.0#;(#,##0.0#)"}.
*
*
The prefixes, suffixes, and various symbols used for infinity, digits,
* thousands separators, decimal separators, etc. may be set to arbitrary
* values, and they will appear properly during formatting. However, care must
* be taken that the symbols and strings do not conflict, or parsing will be
* unreliable. For example, either the positive and negative prefixes or the
- * suffixes must be distinct for DecimalFormat.parse()
to be able
+ * suffixes must be distinct for {@code DecimalFormat.parse()} to be able
* to distinguish positive from negative values. (If they are identical, then
- * DecimalFormat
will behave as if no negative subpattern was
+ * {@code DecimalFormat} will behave as if no negative subpattern was
* specified.) Another example is that the decimal separator and thousands
* separator should be distinct characters, or parsing will be impossible.
*
@@ -151,8 +151,8 @@
* of digits between the grouping characters, such as 3 for 100,000,000 or 4 for
* 1,0000,0000. If you supply a pattern with multiple grouping characters, the
* interval between the last one and the end of the integer is the one that is
- * used. So "#,##,###,####"
== "######,####"
==
- * "##,####,####"
.
+ * used. So {@code "#,##,###,####"} == {@code "######,####"} ==
+ * {@code "##,####,####"}.
*
*
The characters listed here are used in non-localized patterns. Localized
* patterns use the corresponding characters taken from this formatter's
- * DecimalFormatSymbols
object instead, and these characters lose
+ * {@code DecimalFormatSymbols} object instead, and these characters lose
* their special status. Two exceptions are the currency sign and quote, which
* are not localized.
*
@@ -180,53 +180,53 @@
*
*
0
+ * #
+ * .
+ * -
+ * ,
+ * E
+ * ;
+ * %
+ * \u2030
+ * ¤
(\u00A4
)
+ * '
+ * "'#'#"
formats 123 to
- * "#123"
. To create a single quote
- * itself, use two in a row: "# o''clock"
.
+ * for example, {@code "'#'#"} formats 123 to
+ * {@code "#123"}. To create a single quote
+ * itself, use two in a row: {@code "# o''clock"}.
* DecimalFormat
can be instructed to format and parse scientific
+ * {@code DecimalFormat} can be instructed to format and parse scientific
* notation only via a pattern; there is currently no factory method
* that creates a scientific notation format. In a pattern, the exponent
* character immediately followed by one or more digit characters indicates
- * scientific notation. Example: "0.###E0"
formats the number
- * 1234 as "1.234E3"
.
+ * scientific notation. Example: {@code "0.###E0"} formats the number
+ * 1234 as {@code "1.234E3"}.
*
* "0.###E0 m/s"
.
+ * from the pattern. This allows patterns such as {@code "0.###E0 m/s"}.
*
* "##0.#####E0"
. Using this pattern, the number 12345
- * formats to "12.345E3"
, and 123456 formats to
- * "123.456E3"
.
+ * e.g., {@code "##0.#####E0"}. Using this pattern, the number 12345
+ * formats to {@code "12.345E3"}, and 123456 formats to
+ * {@code "123.456E3"}.
*
* "00.###E0"
yields
- * "12.3E-4"
.
+ * exponent. Example: 0.00123 formatted with {@code "00.###E0"} yields
+ * {@code "12.3E-4"}.
* "##0.##E0"
is "12.3E3"
. To show all digits, set
+ * {@code "##0.##E0"} is {@code "12.3E3"}. To show all digits, set
* the significant digits count to zero. The number of significant digits
* does not affect parsing.
*
@@ -294,38 +294,38 @@
*
* DecimalFormat
provides rounding modes defined in
+ * {@code DecimalFormat} provides rounding modes defined in
* {@link java.math.RoundingMode} for formatting. By default, it uses
* {@link java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}.
*
* DecimalFormat
uses the ten consecutive
+ * For formatting, {@code DecimalFormat} uses the ten consecutive
* characters starting with the localized zero digit defined in the
- * DecimalFormatSymbols
object as digits. For parsing, these
+ * {@code DecimalFormatSymbols} object as digits. For parsing, these
* digits as well as all Unicode decimal digits, as defined by
* {@link Character#digit Character.digit}, are recognized.
*
* NaN
is formatted as a string, which typically has a single character
- * \uFFFD
. This string is determined by the
- * DecimalFormatSymbols
object. This is the only value for which
+ *
{@code NaN} is formatted as a string, which typically has a single character + * {@code \uFFFD}. This string is determined by the + * {@code DecimalFormatSymbols} object. This is the only value for which * the prefixes and suffixes are not used. * *
Infinity is formatted as a string, which typically has a single character
- * \u221E
, with the positive or negative prefixes and suffixes
+ * {@code \u221E}, with the positive or negative prefixes and suffixes
* applied. The infinity string is determined by the
- * DecimalFormatSymbols
object.
+ * {@code DecimalFormatSymbols} object.
*
- *
Negative zero ("-0"
) parses to
+ *
Negative zero ({@code "-0"}) parses to *
BigDecimal(0)
if isParseBigDecimal()
is
+ * Long(0)
if isParseBigDecimal()
is false
- * and isParseIntegerOnly()
is true,
- * Double(-0.0)
if both isParseBigDecimal()
- * and isParseIntegerOnly()
are false.
+ * pattern
is null
+ * @exception NullPointerException if {@code pattern} is null
* @exception IllegalArgumentException if the given pattern is invalid.
* @see java.text.NumberFormat#getInstance
* @see java.text.NumberFormat#getNumberInstance
@@ -475,7 +475,7 @@
*
* This implementation uses the maximum precision permitted.
* @param number the number to format
- * @param toAppendTo the StringBuffer
to which the formatted
+ * @param toAppendTo the {@code StringBuffer} to which the formatted
* text is to be appended
* @param pos keeps track on the position of the field within the
* returned string. For example, for formatting a number
@@ -485,11 +485,11 @@
* and end index of {@code fieldPosition} will be set
* to 0 and 9, respectively for the output string
* {@code 1,234,567.89}.
- * @return the value passed in as toAppendTo
- * @exception IllegalArgumentException if number
is
- * null or not an instance of Number
.
- * @exception NullPointerException if toAppendTo
or
- * pos
is null
+ * @return the value passed in as {@code toAppendTo}
+ * @exception IllegalArgumentException if {@code number} is
+ * null or not an instance of {@code Number}.
+ * @exception NullPointerException if {@code toAppendTo} or
+ * {@code pos} is null
* @exception ArithmeticException if rounding is needed with rounding
* mode being set to RoundingMode.UNNECESSARY
* @see java.text.FieldPosition
@@ -914,13 +914,13 @@
}
/**
- * Formats an Object producing an AttributedCharacterIterator
.
- * You can use the returned AttributedCharacterIterator
+ * Formats an Object producing an {@code AttributedCharacterIterator}.
+ * You can use the returned {@code AttributedCharacterIterator}
* to build the resulting String, as well as to determine information
* about the resulting String.
*
* Each attribute key of the AttributedCharacterIterator will be of type
- * NumberFormat.Field
, with the attribute value being the
+ * {@code NumberFormat.Field}, with the attribute value being the
* same as the attribute key.
*
* @exception NullPointerException if obj is null.
@@ -1916,7 +1916,7 @@
if (negativeExponent) {
exponent = -exponent;
fieldStart = result.length();
- result.append(symbols.getMinusSign());
+ result.append(symbols.getMinusSignText());
delegate.formatted(Field.EXPONENT_SIGN, Field.EXPONENT_SIGN,
fieldStart, result.length(), result);
}
@@ -2042,17 +2042,17 @@
}
/**
- * Appends the String string
to result
.
- * delegate
is notified of all the
- * FieldPosition
s in positions
.
+ * Appends the String {@code string} to {@code result}.
+ * {@code delegate} is notified of all the
+ * {@code FieldPosition}s in {@code positions}.
*
- * If one of the FieldPosition
s in positions
- * identifies a SIGN
attribute, it is mapped to
- * signAttribute
. This is used
- * to map the SIGN
attribute to the EXPONENT
+ * If one of the {@code FieldPosition}s in {@code positions}
+ * identifies a {@code SIGN} attribute, it is mapped to
+ * {@code signAttribute}. This is used
+ * to map the {@code SIGN} attribute to the {@code EXPONENT}
* attribute as necessary.
*
- * This is used by subformat
to add the prefix/suffix.
+ * This is used by {@code subformat} to add the prefix/suffix.
*/
private void append(StringBuffer result, String string,
FieldDelegate delegate,
@@ -2078,60 +2078,60 @@
}
/**
- * Parses text from a string to produce a Number
.
+ * Parses text from a string to produce a {@code Number}.
*
* The method attempts to parse text starting at the index given by
- * pos
.
- * If parsing succeeds, then the index of pos
is updated
+ * {@code pos}.
+ * If parsing succeeds, then the index of {@code pos} is updated
* to the index after the last character used (parsing does not necessarily
* use all characters up to the end of the string), and the parsed
- * number is returned. The updated pos
can be used to
+ * number is returned. The updated {@code pos} can be used to
* indicate the starting point for the next call to this method.
- * If an error occurs, then the index of pos
is not
- * changed, the error index of pos
is set to the index of
+ * If an error occurs, then the index of {@code pos} is not
+ * changed, the error index of {@code pos} is set to the index of
* the character where the error occurred, and null is returned.
*
* The subclass returned depends on the value of {@link #isParseBigDecimal} * as well as on the string being parsed. *
isParseBigDecimal()
is false (the default),
- * most integer values are returned as Long
- * objects, no matter how they are written: "17"
and
- * "17.000"
both parse to Long(17)
.
- * Values that cannot fit into a Long
are returned as
- * Double
s. This includes values with a fractional part,
- * infinite values, NaN
, and the value -0.0.
- * DecimalFormat
does not decide whether to
- * return a Double
or a Long
based on the
+ * "-9,223,372,036,854,775,808.00"
, from being
+ * such as {@code "-9,223,372,036,854,775,808.00"}, from being
* parsed accurately.
*
- * Callers may use the Number
methods
- * doubleValue
, longValue
, etc., to obtain
+ * Callers may use the {@code Number} methods
+ * {@code doubleValue}, {@code longValue}, etc., to obtain
* the type they want.
- *
isParseBigDecimal()
is true, values are returned
- * as BigDecimal
objects. The values are the ones
+ * Double
instances holding the values of the
- * corresponding Double
constants.
+ * as {@code Double} instances holding the values of the
+ * corresponding {@code Double} constants.
*
- * Example Example {@code "#,#00.0#"} → 1,234.56
* This means a minimum of 2 integer digits, 1 fraction digit, and
* a maximum of 2 fraction digits.
- * Example: Example: {@code "#,#00.0#;(#,#00.0#)"} for negatives in
* parentheses.
* In negative patterns, the minimum and maximum counts are ignored;
* these are presumed to be set in the positive pattern.
*
* @param pattern a new pattern
- * @exception NullPointerException if Example Example {@code "#,#00.0#"} → 1,234.56
* This means a minimum of 2 integer digits, 1 fraction digit, and
* a maximum of 2 fraction digits.
- * Example: Example: {@code "#,#00.0#;(#,#00.0#)"} for negatives in
* parentheses.
* In negative patterns, the minimum and maximum counts are ignored;
* these are presumed to be set in the positive pattern.
*
* @param pattern a new pattern
- * @exception NullPointerException if Stream versions older than 2 will not have the affix pattern variables
- * This pattern is expanded by the method This pattern is expanded by the method {@code expandAffix()} to
+ * {@code positivePrefix} to update the latter to reflect changes in
+ * {@code symbols}. If this variable is {@code null} then
+ * {@code positivePrefix} is taken as a literal value that does not
+ * change when {@code symbols} changes. This variable is always
+ * {@code null} for {@code DecimalFormat} objects older than
* stream version 2 restored from stream.
*
* @serial
@@ -3977,8 +3967,8 @@
/**
* The suffix pattern for non-negative numbers. This variable corresponds
- * to If the locale contains "rg" (region override)
* Unicode extension,
@@ -107,7 +109,7 @@
* instead of the Latin numbering system.
*
* @param locale the desired locale
- * @exception NullPointerException if
- * If both DecimalFormat
parses all Unicode characters that represent
- * decimal digits, as defined by Character.digit()
. In
- * addition, DecimalFormat
also recognizes as digits the ten
+ * {@code DecimalFormat} parses all Unicode characters that represent
+ * decimal digits, as defined by {@code Character.digit()}. In
+ * addition, {@code DecimalFormat} also recognizes as digits the ten
* consecutive characters starting with the localized zero digit defined in
- * the DecimalFormatSymbols
object.
+ * the {@code DecimalFormatSymbols} object.
*
* @param text the string to be parsed
- * @param pos A ParsePosition
object with index and error
+ * @param pos A {@code ParsePosition} object with index and error
* index information as described above.
- * @return the parsed value, or null
if the parse fails
- * @exception NullPointerException if text
or
- * pos
is null.
+ * @return the parsed value, or {@code null} if the parse fails
+ * @exception NullPointerException if {@code text} or
+ * {@code pos} is null.
*/
@Override
public Number parse(String text, ParsePosition pos) {
@@ -2475,7 +2475,7 @@
boolean[] stat = new boolean[STATUS_LENGTH];
DigitList exponentDigits = new DigitList();
- if (subparse(text, pos, "", Character.toString(symbols.getMinusSign()), exponentDigits, true, stat) &&
+ if (subparse(text, pos, "", symbols.getMinusSignText(), exponentDigits, true, stat) &&
exponentDigits.fitsIntoLong(stat[STATUS_POSITIVE], true)) {
position = pos.index; // Advance past the exponent
exponent = (int)exponentDigits.getLong();
@@ -2573,7 +2573,7 @@
/**
* Returns the FieldPositions of the fields in the prefix used for
* positive numbers. This is not used if the user has explicitly set
- * a positive prefix via setPositivePrefix
. This is
+ * a positive prefix via {@code setPositivePrefix}. This is
* lazily created.
*
* @return FieldPositions in positive prefix
@@ -2614,7 +2614,7 @@
/**
* Returns the FieldPositions of the fields in the prefix used for
* negative numbers. This is not used if the user has explicitly set
- * a negative prefix via setNegativePrefix
. This is
+ * a negative prefix via {@code setNegativePrefix}. This is
* lazily created.
*
* @return FieldPositions in positive prefix
@@ -2655,7 +2655,7 @@
/**
* Returns the FieldPositions of the fields in the suffix used for
* positive numbers. This is not used if the user has explicitly set
- * a positive suffix via setPositiveSuffix
. This is
+ * a positive suffix via {@code setPositiveSuffix}. This is
* lazily created.
*
* @return FieldPositions in positive prefix
@@ -2696,7 +2696,7 @@
/**
* Returns the FieldPositions of the fields in the suffix used for
* negative numbers. This is not used if the user has explicitly set
- * a negative suffix via setNegativeSuffix
. This is
+ * a negative suffix via {@code setNegativeSuffix}. This is
* lazily created.
*
* @return FieldPositions in positive prefix
@@ -2811,7 +2811,7 @@
/**
* Returns whether the {@link #parse(java.lang.String, java.text.ParsePosition)}
- * method returns BigDecimal
. The default value is false.
+ * method returns {@code BigDecimal}. The default value is false.
*
* @return {@code true} if the parse method returns BigDecimal;
* {@code false} otherwise
@@ -2824,7 +2824,7 @@
/**
* Sets whether the {@link #parse(java.lang.String, java.text.ParsePosition)}
- * method returns BigDecimal
.
+ * method returns {@code BigDecimal}.
*
* @param newValue {@code true} if the parse method returns BigDecimal;
* {@code false} otherwise
@@ -2991,14 +2991,14 @@
}
continue;
case PATTERN_PERCENT:
- c = symbols.getPercent();
- break;
+ buffer.append(symbols.getPercentText());
+ continue;
case PATTERN_PER_MILLE:
- c = symbols.getPerMill();
- break;
+ buffer.append(symbols.getPerMillText());
+ continue;
case PATTERN_MINUS:
- c = symbols.getMinusSign();
- break;
+ buffer.append(symbols.getMinusSignText());
+ continue;
}
}
buffer.append(c);
@@ -3027,12 +3027,11 @@
for (int i=0; i"#,#00.0#"
→ 1,234.56
+ * "#,#00.0#;(#,#00.0#)"
for negatives in
+ * pattern
is null
+ * @exception NullPointerException if {@code pattern} is null
* @exception IllegalArgumentException if the given pattern is invalid.
*/
public void applyPattern(String pattern) {
@@ -3282,16 +3272,16 @@
* by this routine, since that is the typical end-user desire;
* use setMaximumInteger if you want to set a real value.
* For negative numbers, use a second pattern, separated by a semicolon
- * "#,#00.0#"
→ 1,234.56
+ * "#,#00.0#;(#,#00.0#)"
for negatives in
+ * pattern
is null
+ * @exception NullPointerException if {@code pattern} is null
* @exception IllegalArgumentException if the given pattern is invalid.
*/
public void applyLocalizedPattern(String pattern) {
@@ -3309,7 +3299,7 @@
char perMill = PATTERN_PER_MILLE;
char digit = PATTERN_DIGIT;
char separator = PATTERN_SEPARATOR;
- String exponent = PATTERN_EXPONENT;
+ String exponent = PATTERN_EXPONENT;
char minus = PATTERN_MINUS;
if (localized) {
zeroDigit = symbols.getZeroDigit();
@@ -3635,8 +3625,8 @@
/**
* Sets the maximum number of digits allowed in the integer portion of a
* number.
- * For formatting numbers other than BigInteger
and
- * BigDecimal
objects, the lower of newValue
and
+ * For formatting numbers other than {@code BigInteger} and
+ * {@code BigDecimal} objects, the lower of {@code newValue} and
* 309 is used. Negative input values are replaced with 0.
* @see NumberFormat#setMaximumIntegerDigits
*/
@@ -3656,8 +3646,8 @@
/**
* Sets the minimum number of digits allowed in the integer portion of a
* number.
- * For formatting numbers other than BigInteger
and
- * BigDecimal
objects, the lower of newValue
and
+ * For formatting numbers other than {@code BigInteger} and
+ * {@code BigDecimal} objects, the lower of {@code newValue} and
* 309 is used. Negative input values are replaced with 0.
* @see NumberFormat#setMinimumIntegerDigits
*/
@@ -3677,8 +3667,8 @@
/**
* Sets the maximum number of digits allowed in the fraction portion of a
* number.
- * For formatting numbers other than BigInteger
and
- * BigDecimal
objects, the lower of newValue
and
+ * For formatting numbers other than {@code BigInteger} and
+ * {@code BigDecimal} objects, the lower of {@code newValue} and
* 340 is used. Negative input values are replaced with 0.
* @see NumberFormat#setMaximumFractionDigits
*/
@@ -3698,8 +3688,8 @@
/**
* Sets the minimum number of digits allowed in the fraction portion of a
* number.
- * For formatting numbers other than BigInteger
and
- * BigDecimal
objects, the lower of newValue
and
+ * For formatting numbers other than {@code BigInteger} and
+ * {@code BigDecimal} objects, the lower of {@code newValue} and
* 340 is used. Negative input values are replaced with 0.
* @see NumberFormat#setMinimumFractionDigits
*/
@@ -3719,8 +3709,8 @@
/**
* Gets the maximum number of digits allowed in the integer portion of a
* number.
- * For formatting numbers other than BigInteger
and
- * BigDecimal
objects, the lower of the return value and
+ * For formatting numbers other than {@code BigInteger} and
+ * {@code BigDecimal} objects, the lower of the return value and
* 309 is used.
* @see #setMaximumIntegerDigits
*/
@@ -3732,8 +3722,8 @@
/**
* Gets the minimum number of digits allowed in the integer portion of a
* number.
- * For formatting numbers other than BigInteger
and
- * BigDecimal
objects, the lower of the return value and
+ * For formatting numbers other than {@code BigInteger} and
+ * {@code BigDecimal} objects, the lower of the return value and
* 309 is used.
* @see #setMinimumIntegerDigits
*/
@@ -3745,8 +3735,8 @@
/**
* Gets the maximum number of digits allowed in the fraction portion of a
* number.
- * For formatting numbers other than BigInteger
and
- * BigDecimal
objects, the lower of the return value and
+ * For formatting numbers other than {@code BigInteger} and
+ * {@code BigDecimal} objects, the lower of the return value and
* 340 is used.
* @see #setMaximumFractionDigits
*/
@@ -3758,8 +3748,8 @@
/**
* Gets the minimum number of digits allowed in the fraction portion of a
* number.
- * For formatting numbers other than BigInteger
and
- * BigDecimal
objects, the lower of the return value and
+ * For formatting numbers other than {@code BigInteger} and
+ * {@code BigDecimal} objects, the lower of the return value and
* 340 is used.
* @see #setMinimumFractionDigits
*/
@@ -3775,7 +3765,7 @@
* {@link DecimalFormatSymbols#getCurrency DecimalFormatSymbols.getCurrency}
* on this number format's symbols.
*
- * @return the currency used by this decimal format, or null
+ * @return the currency used by this decimal format, or {@code null}
* @since 1.4
*/
@Override
@@ -3792,7 +3782,7 @@
* on this number format's symbols.
*
* @param currency the new currency to be used by this decimal format
- * @exception NullPointerException if currency
is null
+ * @exception NullPointerException if {@code currency} is null
* @since 1.4
*/
@Override
@@ -3809,7 +3799,7 @@
/**
* Gets the {@link java.math.RoundingMode} used in this DecimalFormat.
*
- * @return The RoundingMode
used for this DecimalFormat.
+ * @return The {@code RoundingMode} used for this DecimalFormat.
* @see #setRoundingMode(RoundingMode)
* @since 1.6
*/
@@ -3821,9 +3811,9 @@
/**
* Sets the {@link java.math.RoundingMode} used in this DecimalFormat.
*
- * @param roundingMode The RoundingMode
to be used
+ * @param roundingMode The {@code RoundingMode} to be used
* @see #getRoundingMode()
- * @exception NullPointerException if roundingMode
is null.
+ * @exception NullPointerException if {@code roundingMode} is null.
* @since 1.6
*/
@Override
@@ -3845,38 +3835,38 @@
* BigInteger
and BigDecimal
objects. These
+ * {@code BigInteger} and {@code BigDecimal} objects. These
* limits are stored in the superclass for serialization compatibility
- * with older versions, while the limits for BigInteger
and
- * BigDecimal
objects are kept in this class.
+ * with older versions, while the limits for {@code BigInteger} and
+ * {@code BigDecimal} objects are kept in this class.
* If, in the superclass, the minimum or maximum integer digit count is
- * larger than DOUBLE_INTEGER_DIGITS
or if the minimum or
+ * larger than {@code DOUBLE_INTEGER_DIGITS} or if the minimum or
* maximum fraction digit count is larger than
- * DOUBLE_FRACTION_DIGITS
, then the stream data is invalid
- * and this method throws an InvalidObjectException
.
+ * {@code DOUBLE_FRACTION_DIGITS}, then the stream data is invalid
+ * and this method throws an {@code InvalidObjectException}.
* serialVersionOnStream
is less than 4, initialize
- * roundingMode
to {@link java.math.RoundingMode#HALF_EVEN
+ * If {@code serialVersionOnStream} is less than 4, initialize
+ * {@code roundingMode} to {@link java.math.RoundingMode#HALF_EVEN
* RoundingMode.HALF_EVEN}. This field is new with version 4.
* serialVersionOnStream
is less than 3, then call
+ * If {@code serialVersionOnStream} is less than 3, then call
* the setters for the minimum and maximum integer and fraction digits with
* the values of the corresponding superclass getters to initialize the
* fields in this class. The fields in this class are new with version 3.
* serialVersionOnStream
is less than 1, indicating that
+ * If {@code serialVersionOnStream} is less than 1, indicating that
* the stream was written by JDK 1.1, initialize
- * useExponentialNotation
+ * {@code useExponentialNotation}
* to false, since it was not present in JDK 1.1.
* serialVersionOnStream
to the maximum allowed value so
+ * Set {@code serialVersionOnStream} to the maximum allowed value so
* that default serialization will work properly if this object is streamed
* out again.
*
*
* posPrefixPattern
etc. As a result, they will be initialized
- * to null
, which means the affix strings will be taken as
+ * {@code posPrefixPattern} etc. As a result, they will be initialized
+ * to {@code null}, which means the affix strings will be taken as
* literal values. This is exactly what we want, since that corresponds to
* the pre-version-2 behavior.
*/
@@ -3960,14 +3950,14 @@
/**
* The prefix pattern for non-negative numbers. This variable corresponds
- * to positivePrefix
.
+ * to {@code positivePrefix}.
*
- * expandAffix()
to
- * positivePrefix
to update the latter to reflect changes in
- * symbols
. If this variable is null
then
- * positivePrefix
is taken as a literal value that does not
- * change when symbols
changes. This variable is always
- * null
for DecimalFormat
objects older than
+ * positiveSuffix
. This variable is analogous to
- * posPrefixPattern
; see that variable for further
+ * to {@code positiveSuffix}. This variable is analogous to
+ * {@code posPrefixPattern}; see that variable for further
* documentation.
*
* @serial
@@ -3988,8 +3978,8 @@
/**
* The prefix pattern for negative numbers. This variable corresponds
- * to negativePrefix
. This variable is analogous to
- * posPrefixPattern
; see that variable for further
+ * to {@code negativePrefix}. This variable is analogous to
+ * {@code posPrefixPattern}; see that variable for further
* documentation.
*
* @serial
@@ -3999,8 +3989,8 @@
/**
* The suffix pattern for negative numbers. This variable corresponds
- * to negativeSuffix
. This variable is analogous to
- * posPrefixPattern
; see that variable for further
+ * to {@code negativeSuffix}. This variable is analogous to
+ * {@code posPrefixPattern}; see that variable for further
* documentation.
*
* @serial
@@ -4019,7 +4009,7 @@
/**
* The number of digits between grouping separators in the integer
* portion of a number. Must be greater than 0 if
- * NumberFormat.groupingUsed
is true.
+ * {@code NumberFormat.groupingUsed} is true.
*
* @serial
* @see #getGroupingSize
@@ -4053,7 +4043,7 @@
private transient boolean isCurrencyFormat = false;
/**
- * The DecimalFormatSymbols
object used by this format.
+ * The {@code DecimalFormatSymbols} object used by this format.
* It contains the symbols used to format numbers, e.g. the grouping separator,
* decimal separator, and so on.
*
@@ -4074,28 +4064,28 @@
/**
* FieldPositions describing the positive prefix String. This is
- * lazily created. Use getPositivePrefixFieldPositions
+ * lazily created. Use {@code getPositivePrefixFieldPositions}
* when needed.
*/
private transient FieldPosition[] positivePrefixFieldPositions;
/**
* FieldPositions describing the positive suffix String. This is
- * lazily created. Use getPositiveSuffixFieldPositions
+ * lazily created. Use {@code getPositiveSuffixFieldPositions}
* when needed.
*/
private transient FieldPosition[] positiveSuffixFieldPositions;
/**
* FieldPositions describing the negative prefix String. This is
- * lazily created. Use getNegativePrefixFieldPositions
+ * lazily created. Use {@code getNegativePrefixFieldPositions}
* when needed.
*/
private transient FieldPosition[] negativePrefixFieldPositions;
/**
* FieldPositions describing the negative suffix String. This is
- * lazily created. Use getNegativeSuffixFieldPositions
+ * lazily created. Use {@code getNegativeSuffixFieldPositions}
* when needed.
*/
private transient FieldPosition[] negativeSuffixFieldPositions;
@@ -4103,7 +4093,7 @@
/**
* The minimum number of digits used to display the exponent when a number is
* formatted in exponential notation. This field is ignored if
- * useExponentialNotation
is not true.
+ * {@code useExponentialNotation} is not true.
*
* @serial
* @since 1.2
@@ -4112,9 +4102,9 @@
/**
* The maximum number of digits allowed in the integer portion of a
- * BigInteger
or BigDecimal
number.
- * maximumIntegerDigits
must be greater than or equal to
- * minimumIntegerDigits
.
+ * {@code BigInteger} or {@code BigDecimal} number.
+ * {@code maximumIntegerDigits} must be greater than or equal to
+ * {@code minimumIntegerDigits}.
*
* @serial
* @see #getMaximumIntegerDigits
@@ -4124,9 +4114,9 @@
/**
* The minimum number of digits allowed in the integer portion of a
- * BigInteger
or BigDecimal
number.
- * minimumIntegerDigits
must be less than or equal to
- * maximumIntegerDigits
.
+ * {@code BigInteger} or {@code BigDecimal} number.
+ * {@code minimumIntegerDigits} must be less than or equal to
+ * {@code maximumIntegerDigits}.
*
* @serial
* @see #getMinimumIntegerDigits
@@ -4136,9 +4126,9 @@
/**
* The maximum number of digits allowed in the fractional portion of a
- * BigInteger
or BigDecimal
number.
- * maximumFractionDigits
must be greater than or equal to
- * minimumFractionDigits
.
+ * {@code BigInteger} or {@code BigDecimal} number.
+ * {@code maximumFractionDigits} must be greater than or equal to
+ * {@code minimumFractionDigits}.
*
* @serial
* @see #getMaximumFractionDigits
@@ -4148,9 +4138,9 @@
/**
* The minimum number of digits allowed in the fractional portion of a
- * BigInteger
or BigDecimal
number.
- * minimumFractionDigits
must be less than or equal to
- * maximumFractionDigits
.
+ * {@code BigInteger} or {@code BigDecimal} number.
+ * {@code minimumFractionDigits} must be less than or equal to
+ * {@code maximumFractionDigits}.
*
* @serial
* @see #getMinimumFractionDigits
@@ -4247,19 +4237,19 @@
*
*
* @since 1.2
* @serial
diff -r 51195881bd3a -r 83deaa8f0c8e src/java.base/share/classes/java/text/DecimalFormatSymbols.java
--- a/src/java.base/share/classes/java/text/DecimalFormatSymbols.java Fri Mar 22 08:18:26 2019 -0700
+++ b/src/java.base/share/classes/java/text/DecimalFormatSymbols.java Fri Mar 22 09:31:36 2019 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -38,12 +38,14 @@
package java.text;
+import java.io.InvalidObjectException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.text.spi.DecimalFormatSymbolsProvider;
import java.util.Currency;
import java.util.Locale;
+import java.util.Objects;
import sun.util.locale.provider.CalendarDataUtility;
import sun.util.locale.provider.LocaleProviderAdapter;
import sun.util.locale.provider.LocaleServiceProviderPool;
@@ -51,11 +53,11 @@
/**
* This class represents the set of symbols (such as the decimal separator,
- * the grouping separator, and so on) needed by useExponentialNotation
and
- * minExponentDigits
.
+ * {@code useExponentialNotation} and
+ * {@code minExponentDigits}.
* posPrefixPattern
, posSuffixPattern
,
- * negPrefixPattern
, and negSuffixPattern
.
+ * {@code posPrefixPattern}, {@code posSuffixPattern},
+ * {@code negPrefixPattern}, and {@code negSuffixPattern}.
* maximumIntegerDigits
,
- * minimumIntegerDigits
,
- * maximumFractionDigits
,
- * minimumFractionDigits
, and
- * parseBigDecimal
.
+ * {@code maximumIntegerDigits},
+ * {@code minimumIntegerDigits},
+ * {@code maximumFractionDigits},
+ * {@code minimumFractionDigits}, and
+ * {@code parseBigDecimal}.
* roundingMode
.
+ * {@code roundingMode}.
* DecimalFormat
- * to format numbers. DecimalFormat
creates for itself an instance of
- * DecimalFormatSymbols
from its locale data. If you need to change any
- * of these symbols, you can get the DecimalFormatSymbols
object from
- * your DecimalFormat
and modify it.
+ * the grouping separator, and so on) needed by {@code DecimalFormat}
+ * to format numbers. {@code DecimalFormat} creates for itself an instance of
+ * {@code DecimalFormatSymbols} from its locale data. If you need to change any
+ * of these symbols, you can get the {@code DecimalFormatSymbols} object from
+ * your {@code DecimalFormat} and modify it.
*
* locale
is null
+ * @exception NullPointerException if {@code locale} is null
*/
public DecimalFormatSymbols( Locale locale ) {
initialize( locale );
@@ -115,16 +117,16 @@
/**
* Returns an array of all locales for which the
- * getInstance
methods of this class can return
+ * {@code getInstance} methods of this class can return
* localized instances.
* The returned array represents the union of locales supported by the Java
* runtime and by installed
* {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
- * implementations. It must contain at least a Locale
+ * implementations. It must contain at least a {@code Locale}
* instance equal to {@link java.util.Locale#US Locale.US}.
*
* @return an array of locales for which localized
- * DecimalFormatSymbols
instances are available.
+ * {@code DecimalFormatSymbols} instances are available.
* @since 1.6
*/
public static Locale[] getAvailableLocales() {
@@ -134,8 +136,8 @@
}
/**
- * Gets the DecimalFormatSymbols
instance for the default
- * locale. This method provides access to DecimalFormatSymbols
+ * Gets the {@code DecimalFormatSymbols} instance for the default
+ * locale. This method provides access to {@code DecimalFormatSymbols}
* instances for locales supported by the Java runtime itself as well
* as for those supported by installed
* {@link java.text.spi.DecimalFormatSymbolsProvider
@@ -145,7 +147,7 @@
* getInstance(Locale.getDefault(Locale.Category.FORMAT))}.
* @see java.util.Locale#getDefault(java.util.Locale.Category)
* @see java.util.Locale.Category#FORMAT
- * @return a DecimalFormatSymbols
instance.
+ * @return a {@code DecimalFormatSymbols} instance.
* @since 1.6
*/
public static final DecimalFormatSymbols getInstance() {
@@ -153,8 +155,8 @@
}
/**
- * Gets the DecimalFormatSymbols
instance for the specified
- * locale. This method provides access to DecimalFormatSymbols
+ * Gets the {@code DecimalFormatSymbols} instance for the specified
+ * locale. This method provides access to {@code DecimalFormatSymbols}
* instances for locales supported by the Java runtime itself as well
* as for those supported by installed
* {@link java.text.spi.DecimalFormatSymbolsProvider
@@ -169,8 +171,8 @@
* instead of the Latin numbering system.
*
* @param locale the desired locale.
- * @return a DecimalFormatSymbols
instance.
- * @exception NullPointerException if locale
is null
+ * @return a {@code DecimalFormatSymbols} instance.
+ * @exception NullPointerException if {@code locale} is null
* @since 1.6
*/
public static final DecimalFormatSymbols getInstance(Locale locale) {
@@ -255,6 +257,41 @@
*/
public void setPerMill(char perMill) {
this.perMill = perMill;
+ this.perMillText = Character.toString(perMill);
+ }
+
+ /**
+ * Gets the string used for per mille sign. Different for Arabic, etc.
+ *
+ * @return the string used for per mille sign
+ * @since 13
+ */
+ String getPerMillText() {
+ return perMillText;
+ }
+
+ /**
+ * Sets the string used for per mille sign. Different for Arabic, etc.
+ *
+ * Setting the {@code perMillText} affects the return value of
+ * {@link #getPerMill()}, in which the first non-format character of
+ * {@code perMillText} is returned.
+ *
+ * @param perMillText the string used for per mille sign
+ * @throws NullPointerException if {@code perMillText} is null
+ * @throws IllegalArgumentException if {@code perMillText} is an empty string
+ * @see #getPerMill()
+ * @see #getPerMillText()
+ * @since 13
+ */
+ void setPerMillText(String perMillText) {
+ Objects.requireNonNull(perMillText);
+ if (perMillText.isEmpty()) {
+ throw new IllegalArgumentException("Empty argument string");
+ }
+
+ this.perMillText = perMillText;
+ this.perMill = findNonFormatChar(perMillText, '\u2030');
}
/**
@@ -273,6 +310,41 @@
*/
public void setPercent(char percent) {
this.percent = percent;
+ this.percentText = Character.toString(percent);
+ }
+
+ /**
+ * Gets the string used for percent sign. Different for Arabic, etc.
+ *
+ * @return the string used for percent sign
+ * @since 13
+ */
+ String getPercentText() {
+ return percentText;
+ }
+
+ /**
+ * Sets the string used for percent sign. Different for Arabic, etc.
+ *
+ * Setting the {@code percentText} affects the return value of
+ * {@link #getPercent()}, in which the first non-format character of
+ * {@code percentText} is returned.
+ *
+ * @param percentText the string used for percent sign
+ * @throws NullPointerException if {@code percentText} is null
+ * @throws IllegalArgumentException if {@code percentText} is an empty string
+ * @see #getPercent()
+ * @see #getPercentText()
+ * @since 13
+ */
+ void setPercentText(String percentText) {
+ Objects.requireNonNull(percentText);
+ if (percentText.isEmpty()) {
+ throw new IllegalArgumentException("Empty argument string");
+ }
+
+ this.percentText = percentText;
+ this.percent = findNonFormatChar(percentText, '%');
}
/**
@@ -373,6 +445,46 @@
*/
public void setMinusSign(char minusSign) {
this.minusSign = minusSign;
+ this.minusSignText = Character.toString(minusSign);
+ }
+
+ /**
+ * Gets the string used to represent minus sign. If no explicit
+ * negative format is specified, one is formed by prefixing
+ * minusSignText to the positive format.
+ *
+ * @return the string representing minus sign
+ * @since 13
+ */
+ String getMinusSignText() {
+ return minusSignText;
+ }
+
+ /**
+ * Sets the string used to represent minus sign. If no explicit
+ * negative format is specified, one is formed by prefixing
+ * minusSignText to the positive format.
+ *
+ * Setting the {@code minusSignText} affects the return value of
+ * {@link #getMinusSign()}, in which the first non-format character of
+ * {@code minusSignText} is returned.
+ *
+ * @param minusSignText the character representing minus sign
+ * @throws NullPointerException if {@code minusSignText} is null
+ * @throws IllegalArgumentException if {@code minusSignText} is an
+ * empty string
+ * @see #getMinusSign()
+ * @see #getMinusSignText()
+ * @since 13
+ */
+ void setMinusSignText(String minusSignText) {
+ Objects.requireNonNull(minusSignText);
+ if (minusSignText.isEmpty()) {
+ throw new IllegalArgumentException("Empty argument string");
+ }
+
+ this.minusSignText = minusSignText;
+ this.minusSign = findNonFormatChar(minusSignText, '-');
}
/**
@@ -464,7 +576,7 @@
* symbol attribute to the currency's ISO 4217 currency code.
*
* @param currency the new currency to be used
- * @exception NullPointerException if currency
is null
+ * @exception NullPointerException if {@code currency} is null
* @since 1.4
* @see #setCurrencySymbol
* @see #setInternationalCurrencySymbol
@@ -540,7 +652,7 @@
* Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
*
* @param exp the exponent separator string
- * @exception NullPointerException if exp
is null
+ * @exception NullPointerException if {@code exp} is null
* @see #getExponentSeparator()
* @since 1.6
*/
@@ -583,9 +695,12 @@
groupingSeparator == other.groupingSeparator &&
decimalSeparator == other.decimalSeparator &&
percent == other.percent &&
+ percentText.equals(other.percentText) &&
perMill == other.perMill &&
+ perMillText.equals(other.perMillText) &&
digit == other.digit &&
minusSign == other.minusSign &&
+ minusSignText.equals(other.minusSignText) &&
patternSeparator == other.patternSeparator &&
infinity.equals(other.infinity) &&
NaN.equals(other.NaN) &&
@@ -631,13 +746,16 @@
decimalSeparator = numberElements[0].charAt(0);
groupingSeparator = numberElements[1].charAt(0);
patternSeparator = numberElements[2].charAt(0);
- percent = numberElements[3].charAt(0);
+ percentText = numberElements[3];
+ percent = findNonFormatChar(percentText, '%');
zeroDigit = numberElements[4].charAt(0); //different for Arabic,etc.
digit = numberElements[5].charAt(0);
- minusSign = numberElements[6].charAt(0);
+ minusSignText = numberElements[6];
+ minusSign = findNonFormatChar(minusSignText, '-');
exponential = numberElements[7].charAt(0);
exponentialSeparator = numberElements[7]; //string representation new since 1.6
- perMill = numberElements[8].charAt(0);
+ perMillText = numberElements[8];
+ perMill = findNonFormatChar(perMillText, '\u2030');
infinity = numberElements[9];
NaN = numberElements[10];
@@ -652,6 +770,16 @@
}
/**
+ * Obtains non-format single character from String
+ */
+ private char findNonFormatChar(String src, char defChar) {
+ return (char)src.chars()
+ .filter(c -> Character.getType(c) != Character.FORMAT)
+ .findFirst()
+ .orElse(defChar);
+ }
+
+ /**
* Lazy initialization for currency related fields
*/
private void initializeCurrency(Locale locale) {
@@ -704,18 +832,24 @@
/**
* Reads the default serializable fields, provides default values for objects
* in older serial versions, and initializes non-serializable fields.
- * If serialVersionOnStream
- * is less than 1, initializes monetarySeparator
to be
- * the same as decimalSeparator
and exponential
+ * If {@code serialVersionOnStream}
+ * is less than 1, initializes {@code monetarySeparator} to be
+ * the same as {@code decimalSeparator} and {@code exponential}
* to be 'E'.
- * If serialVersionOnStream
is less than 2,
- * initializes locale
to the root locale, and initializes
- * If serialVersionOnStream
is less than 3, it initializes
- * exponentialSeparator
using exponential
.
- * Sets serialVersionOnStream
back to the maximum allowed value so that
+ * If {@code serialVersionOnStream} is less than 2,
+ * initializes {@code locale}to the root locale, and initializes
+ * If {@code serialVersionOnStream} is less than 3, it initializes
+ * {@code exponentialSeparator} using {@code exponential}.
+ * If {@code serialVersionOnStream} is less than 4, it initializes
+ * {@code perMillText}, {@code percentText}, and
+ * {@code minusSignText} using {@code perMill}, {@code percent}, and
+ * {@code minusSign} respectively.
+ * Sets {@code serialVersionOnStream} back to the maximum allowed value so that
* default serialization will work properly if this object is streamed out again.
* Initializes the currency from the intlCurrencySymbol field.
*
+ * @throws InvalidObjectException if {@code char} and {@code String}
+ * representations of either percent, per mille, and/or minus sign disagree.
* @since 1.1.6
*/
private void readObject(ObjectInputStream stream)
@@ -735,6 +869,23 @@
// didn't have exponentialSeparator. Create one using exponential
exponentialSeparator = Character.toString(exponential);
}
+ if (serialVersionOnStream < 4) {
+ // didn't have perMillText, percentText, and minusSignText.
+ // Create one using corresponding char variations.
+ perMillText = Character.toString(perMill);
+ percentText = Character.toString(percent);
+ minusSignText = Character.toString(minusSign);
+ } else {
+ // Check whether char and text fields agree
+ if (findNonFormatChar(perMillText, '\uFFFF') != perMill ||
+ findNonFormatChar(percentText, '\uFFFF') != percent ||
+ findNonFormatChar(minusSignText, '\uFFFF') != minusSign) {
+ throw new InvalidObjectException(
+ "'char' and 'String' representations of either percent, " +
+ "per mille, and/or minus sign disagree.");
+ }
+ }
+
serialVersionOnStream = currentSerialVersion;
if (intlCurrencySymbol != null) {
@@ -862,8 +1013,8 @@
* The string used to separate the mantissa from the exponent.
* Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
* exponential
and exponentialSeparator
- * exist, this exponentialSeparator
has the precedence.
+ * If both {@code exponential} and {@code exponentialSeparator}
+ * exist, this {@code exponentialSeparator} has the precedence.
*
* @serial
* @since 1.6
@@ -878,6 +1029,39 @@
*/
private Locale locale;
+ /**
+ * String representation of per mille sign, which may include
+ * formatting characters, such as BiDi control characters.
+ * The first non-format character of this string is the same as
+ * {@code perMill}.
+ *
+ * @serial
+ * @since 13
+ */
+ private String perMillText;
+
+ /**
+ * String representation of percent sign, which may include
+ * formatting characters, such as BiDi control characters.
+ * The first non-format character of this string is the same as
+ * {@code percent}.
+ *
+ * @serial
+ * @since 13
+ */
+ private String percentText;
+
+ /**
+ * String representation of minus sign, which may include
+ * formatting characters, such as BiDi control characters.
+ * The first non-format character of this string is the same as
+ * {@code minusSign}.
+ *
+ * @serial
+ * @since 13
+ */
+ private String minusSignText;
+
// currency; only the ISO code is serialized.
private transient Currency currency;
private transient volatile boolean currencyInitialized;
@@ -891,23 +1075,28 @@
// monetarySeparator and exponential.
// - 2 for version from J2SE 1.4, which includes locale field.
// - 3 for version from J2SE 1.6, which includes exponentialSeparator field.
- private static final int currentSerialVersion = 3;
+ // - 4 for version from Java SE 13, which includes perMillText, percentText,
+ // and minusSignText field.
+ private static final int currentSerialVersion = 4;
/**
- * Describes the version of DecimalFormatSymbols
present on the stream.
+ * Describes the version of {@code DecimalFormatSymbols} present on the stream.
* Possible values are:
*
*
- * When streaming out a monetarySeparator
and exponential
.
+ * two new fields: {@code monetarySeparator} and {@code exponential}.
* locale
field.
+ * new {@code locale} field.
* exponentialSeparator
field.
+ * new {@code exponentialSeparator} field.
+ * DecimalFormatSymbols
, the most recent format
- * (corresponding to the highest allowable serialVersionOnStream
)
+ * When streaming out a {@code DecimalFormatSymbols}, the most recent format
+ * (corresponding to the highest allowable {@code serialVersionOnStream})
* is always written.
*
* @serial
diff -r 51195881bd3a -r 83deaa8f0c8e test/jdk/java/text/Format/NumberFormat/DFSMinusPerCentMill.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/text/Format/NumberFormat/DFSMinusPerCentMill.java Fri Mar 22 09:31:36 2019 -0700
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8220309
+ * @library /java/text/testlib
+ * @summary Test String representation of MinusSign/Percent/PerMill symbols.
+ * This test assumes CLDR has numbering systems for "arab" and
+ * "arabext", and their minus/percent representations include
+ * BiDi formatting control characters.
+ * @run testng/othervm DFSMinusPerCentMill
+ */
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+import static org.testng.Assert.*;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+public class DFSMinusPerCentMill {
+ private enum Type {
+ NUMBER, PERCENT, CURRENCY, INTEGER, COMPACT, PERMILL
+ }
+
+ private static final Locale US_ARAB = Locale.forLanguageTag("en-US-u-nu-arab");
+ private static final Locale US_ARABEXT = Locale.forLanguageTag("en-US-u-nu-arabext");
+ private static final double SRC_NUM = -1234.56;
+
+ @DataProvider
+ Object[][] formatData() {
+ return new Object[][] {
+ // Locale, FormatStyle, expected format, expected single char symbol
+ {US_ARAB, Type.NUMBER, "\u061c-\u0661\u066c\u0662\u0663\u0664\u066b\u0665\u0666"},
+ {US_ARAB, Type.PERCENT, "\u061c-\u0661\u0662\u0663\u066c\u0664\u0665\u0666\u066a\u061c"},
+ {US_ARAB, Type.CURRENCY, "\u061c-$\u0661\u066c\u0662\u0663\u0664\u066b\u0665\u0666"},
+ {US_ARAB, Type.INTEGER, "\u061c-\u0661\u066c\u0662\u0663\u0665"},
+ {US_ARAB, Type.COMPACT, "\u061c-\u0661K"},
+ {US_ARAB, Type.PERMILL, "\u061c-\u0661\u0662\u0663\u0664\u0665\u0666\u0660\u0609"},
+
+ {US_ARABEXT, Type.NUMBER, "\u200e-\u200e\u06f1\u066c\u06f2\u06f3\u06f4\u066b\u06f5\u06f6"},
+ {US_ARABEXT, Type.PERCENT, "\u200e-\u200e\u06f1\u06f2\u06f3\u066c\u06f4\u06f5\u06f6\u066a"},
+ {US_ARABEXT, Type.CURRENCY, "\u200e-\u200e$\u06f1\u066c\u06f2\u06f3\u06f4\u066b\u06f5\u06f6"},
+ {US_ARABEXT, Type.INTEGER, "\u200e-\u200e\u06f1\u066c\u06f2\u06f3\u06f5"},
+ {US_ARABEXT, Type.COMPACT, "\u200e-\u200e\u06f1K"},
+ {US_ARABEXT, Type.PERMILL, "\u200e-\u200e\u06f1\u06f2\u06f3\u06f4\u06f5\u06f6\u06f0\u0609"},
+ };
+ }
+
+ @DataProvider
+ Object[][] charSymbols() {
+ return new Object[][]{
+ // Locale, percent, per mille, minus sign
+ {US_ARAB, '\u066a', '\u0609', '-'},
+ {US_ARABEXT, '\u066a', '\u0609', '-'},
+ };
+ }
+
+ @Test(dataProvider="formatData")
+ public void testFormatData(Locale l, Type style, String expected) {
+ NumberFormat nf = null;
+ switch (style) {
+ case NUMBER:
+ nf = NumberFormat.getNumberInstance(l);
+ break;
+ case PERCENT:
+ nf = NumberFormat.getPercentInstance(l);
+ break;
+ case CURRENCY:
+ nf = NumberFormat.getCurrencyInstance(l);
+ break;
+ case INTEGER:
+ nf = NumberFormat.getIntegerInstance(l);
+ break;
+ case COMPACT:
+ nf = NumberFormat.getCompactNumberInstance(l, NumberFormat.Style.SHORT);
+ break;
+ case PERMILL:
+ nf = new DecimalFormat("#.#\u2030", DecimalFormatSymbols.getInstance(l));
+ break;
+ }
+
+ assertEquals(nf.format(SRC_NUM), expected);
+ }
+
+ @Test(dataProvider="charSymbols")
+ public void testCharSymbols(Locale l, char percent, char permill, char minus) {
+ DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l);
+ assertEquals(dfs.getPercent(), percent);
+ assertEquals(dfs.getPerMill(), permill);
+ assertEquals(dfs.getMinusSign(), minus);
+ }
+
+ @Test
+ public void testSerialization() throws Exception {
+ DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance();
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ new ObjectOutputStream(bos).writeObject(dfs);
+ DecimalFormatSymbols dfsSerialized = (DecimalFormatSymbols)new ObjectInputStream(
+ new ByteArrayInputStream(bos.toByteArray())
+ ).readObject();
+
+ assertEquals(dfs, dfsSerialized);
+
+ // set minus/percent/permille
+ dfs.setMinusSign('a');
+ dfs.setPercent('b');
+ dfs.setPerMill('c');
+ bos = new ByteArrayOutputStream();
+ new ObjectOutputStream(bos).writeObject(dfs);
+ dfsSerialized = (DecimalFormatSymbols)new ObjectInputStream(
+ new ByteArrayInputStream(bos.toByteArray())
+ ).readObject();
+
+ assertEquals(dfs, dfsSerialized);
+ }
+}