< prev index next >

src/java.base/share/classes/java/text/DecimalFormatSymbols.java

Print this page
rev 54198 : [mq]: 8220224

*** 1,7 **** /* ! * Copyright (c) 1996, 2017, 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. Oracle designates this --- 1,7 ---- /* ! * 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 * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this
*** 36,63 **** * */ package java.text; 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 sun.util.locale.provider.CalendarDataUtility; import sun.util.locale.provider.LocaleProviderAdapter; import sun.util.locale.provider.LocaleServiceProviderPool; import sun.util.locale.provider.ResourceBundleBasedAdapter; /** * This class represents the set of symbols (such as the decimal separator, ! * the grouping separator, and so on) needed by <code>DecimalFormat</code> ! * to format numbers. <code>DecimalFormat</code> creates for itself an instance of ! * <code>DecimalFormatSymbols</code> from its locale data. If you need to change any ! * of these symbols, you can get the <code>DecimalFormatSymbols</code> object from ! * your <code>DecimalFormat</code> and modify it. * * <p>If the locale contains "rg" (region override) * <a href="../util/Locale.html#def_locale_extension">Unicode extension</a>, * the symbols are overridden for the designated region. * --- 36,65 ---- * */ 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; import sun.util.locale.provider.ResourceBundleBasedAdapter; /** * This class represents the set of symbols (such as the decimal separator, ! * 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. * * <p>If the locale contains "rg" (region override) * <a href="../util/Locale.html#def_locale_extension">Unicode extension</a>, * the symbols are overridden for the designated region. *
*** 105,162 **** * </pre> * This may return a {@code NumberFormat} instance with the Thai numbering system, * instead of the Latin numbering system. * * @param locale the desired locale ! * @exception NullPointerException if <code>locale</code> is null */ public DecimalFormatSymbols( Locale locale ) { initialize( locale ); } /** * Returns an array of all locales for which the ! * <code>getInstance</code> 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 <code>Locale</code> * instance equal to {@link java.util.Locale#US Locale.US}. * * @return an array of locales for which localized ! * <code>DecimalFormatSymbols</code> instances are available. * @since 1.6 */ public static Locale[] getAvailableLocales() { LocaleServiceProviderPool pool = LocaleServiceProviderPool.getPool(DecimalFormatSymbolsProvider.class); return pool.getAvailableLocales(); } /** ! * Gets the <code>DecimalFormatSymbols</code> instance for the default ! * locale. This method provides access to <code>DecimalFormatSymbols</code> * instances for locales supported by the Java runtime itself as well * as for those supported by installed * {@link java.text.spi.DecimalFormatSymbolsProvider * DecimalFormatSymbolsProvider} implementations. * <p>This is equivalent to calling * {@link #getInstance(Locale) * getInstance(Locale.getDefault(Locale.Category.FORMAT))}. * @see java.util.Locale#getDefault(java.util.Locale.Category) * @see java.util.Locale.Category#FORMAT ! * @return a <code>DecimalFormatSymbols</code> instance. * @since 1.6 */ public static final DecimalFormatSymbols getInstance() { return getInstance(Locale.getDefault(Locale.Category.FORMAT)); } /** ! * Gets the <code>DecimalFormatSymbols</code> instance for the specified ! * locale. This method provides access to <code>DecimalFormatSymbols</code> * instances for locales supported by the Java runtime itself as well * as for those supported by installed * {@link java.text.spi.DecimalFormatSymbolsProvider * DecimalFormatSymbolsProvider} implementations. * If the specified locale contains the {@link java.util.Locale#UNICODE_LOCALE_EXTENSION} --- 107,164 ---- * </pre> * This may return a {@code NumberFormat} instance with the Thai numbering system, * instead of the Latin numbering system. * * @param locale the desired locale ! * @exception NullPointerException if {@code locale} is null */ public DecimalFormatSymbols( Locale locale ) { initialize( locale ); } /** * Returns an array of all locales for which the ! * {@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 {@code Locale} * instance equal to {@link java.util.Locale#US Locale.US}. * * @return an array of locales for which localized ! * {@code DecimalFormatSymbols} instances are available. * @since 1.6 */ public static Locale[] getAvailableLocales() { LocaleServiceProviderPool pool = LocaleServiceProviderPool.getPool(DecimalFormatSymbolsProvider.class); return pool.getAvailableLocales(); } /** ! * 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 * DecimalFormatSymbolsProvider} implementations. * <p>This is equivalent to calling * {@link #getInstance(Locale) * getInstance(Locale.getDefault(Locale.Category.FORMAT))}. * @see java.util.Locale#getDefault(java.util.Locale.Category) * @see java.util.Locale.Category#FORMAT ! * @return a {@code DecimalFormatSymbols} instance. * @since 1.6 */ public static final DecimalFormatSymbols getInstance() { return getInstance(Locale.getDefault(Locale.Category.FORMAT)); } /** ! * 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 * DecimalFormatSymbolsProvider} implementations. * If the specified locale contains the {@link java.util.Locale#UNICODE_LOCALE_EXTENSION}
*** 167,178 **** * </pre> * This may return a {@code NumberFormat} instance with the Thai numbering system, * instead of the Latin numbering system. * * @param locale the desired locale. ! * @return a <code>DecimalFormatSymbols</code> instance. ! * @exception NullPointerException if <code>locale</code> is null * @since 1.6 */ public static final DecimalFormatSymbols getInstance(Locale locale) { LocaleProviderAdapter adapter; adapter = LocaleProviderAdapter.getAdapter(DecimalFormatSymbolsProvider.class, locale); --- 169,180 ---- * </pre> * This may return a {@code NumberFormat} instance with the Thai numbering system, * instead of the Latin numbering system. * * @param locale the desired locale. ! * @return a {@code DecimalFormatSymbols} instance. ! * @exception NullPointerException if {@code locale} is null * @since 1.6 */ public static final DecimalFormatSymbols getInstance(Locale locale) { LocaleProviderAdapter adapter; adapter = LocaleProviderAdapter.getAdapter(DecimalFormatSymbolsProvider.class, locale);
*** 253,262 **** --- 255,299 ---- * * @param perMill the character used for per mille sign */ 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'); } /** * Gets the character used for percent sign. Different for Arabic, etc. *
*** 271,280 **** --- 308,352 ---- * * @param percent the character used for percent sign */ 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, '%'); } /** * Gets the character used for a digit in a pattern. *
*** 371,380 **** --- 443,492 ---- * * @param minusSign the character representing minus sign */ 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, '-'); } /** * Returns the currency symbol for the currency of these * DecimalFormatSymbols in their locale.
*** 462,472 **** * This also sets the currency symbol attribute to the currency's symbol * in the DecimalFormatSymbols' locale, and the international currency * symbol attribute to the currency's ISO 4217 currency code. * * @param currency the new currency to be used ! * @exception NullPointerException if <code>currency</code> is null * @since 1.4 * @see #setCurrencySymbol * @see #setInternationalCurrencySymbol */ public void setCurrency(Currency currency) { --- 574,584 ---- * This also sets the currency symbol attribute to the currency's symbol * in the DecimalFormatSymbols' locale, and the international currency * symbol attribute to the currency's ISO 4217 currency code. * * @param currency the new currency to be used ! * @exception NullPointerException if {@code currency} is null * @since 1.4 * @see #setCurrencySymbol * @see #setInternationalCurrencySymbol */ public void setCurrency(Currency currency) {
*** 538,548 **** /** * Sets the string used to separate the mantissa from the exponent. * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4. * * @param exp the exponent separator string ! * @exception NullPointerException if <code>exp</code> is null * @see #getExponentSeparator() * @since 1.6 */ public void setExponentSeparator(String exp) { --- 650,660 ---- /** * Sets the string used to separate the mantissa from the exponent. * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4. * * @param exp the exponent separator string ! * @exception NullPointerException if {@code exp} is null * @see #getExponentSeparator() * @since 1.6 */ public void setExponentSeparator(String exp) {
*** 581,593 **** --- 693,708 ---- DecimalFormatSymbols other = (DecimalFormatSymbols) obj; return (zeroDigit == other.zeroDigit && 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) && getCurrencySymbol().equals(other.getCurrencySymbol()) && // possible currency init occurs here intlCurrencySymbol.equals(other.intlCurrencySymbol) &&
*** 629,645 **** String[] numberElements = (String[]) data[0]; decimalSeparator = numberElements[0].charAt(0); groupingSeparator = numberElements[1].charAt(0); patternSeparator = numberElements[2].charAt(0); ! percent = numberElements[3].charAt(0); zeroDigit = numberElements[4].charAt(0); //different for Arabic,etc. digit = numberElements[5].charAt(0); ! minusSign = numberElements[6].charAt(0); exponential = numberElements[7].charAt(0); exponentialSeparator = numberElements[7]; //string representation new since 1.6 ! perMill = numberElements[8].charAt(0); infinity = numberElements[9]; NaN = numberElements[10]; // maybe filled with previously cached values, or null. intlCurrencySymbol = (String) data[1]; --- 744,763 ---- String[] numberElements = (String[]) data[0]; decimalSeparator = numberElements[0].charAt(0); groupingSeparator = numberElements[1].charAt(0); patternSeparator = numberElements[2].charAt(0); ! percentText = numberElements[3]; ! percent = findNonFormatChar(percentText, '%'); zeroDigit = numberElements[4].charAt(0); //different for Arabic,etc. digit = numberElements[5].charAt(0); ! minusSignText = numberElements[6]; ! minusSign = findNonFormatChar(minusSignText, '-'); exponential = numberElements[7].charAt(0); exponentialSeparator = numberElements[7]; //string representation new since 1.6 ! perMillText = numberElements[8]; ! perMill = findNonFormatChar(perMillText, '\u2030'); infinity = numberElements[9]; NaN = numberElements[10]; // maybe filled with previously cached values, or null. intlCurrencySymbol = (String) data[1];
*** 650,659 **** --- 768,787 ---- // If that changes, add a new entry to NumberElements. monetarySeparator = decimalSeparator; } /** + * 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) { if (currencyInitialized) { return;
*** 702,723 **** } /** * Reads the default serializable fields, provides default values for objects * in older serial versions, and initializes non-serializable fields. ! * If <code>serialVersionOnStream</code> ! * is less than 1, initializes <code>monetarySeparator</code> to be ! * the same as <code>decimalSeparator</code> and <code>exponential</code> * to be 'E'. ! * If <code>serialVersionOnStream</code> is less than 2, ! * initializes <code>locale</code>to the root locale, and initializes ! * If <code>serialVersionOnStream</code> is less than 3, it initializes ! * <code>exponentialSeparator</code> using <code>exponential</code>. ! * Sets <code>serialVersionOnStream</code> 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. * * @since 1.1.6 */ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { stream.defaultReadObject(); --- 830,857 ---- } /** * Reads the default serializable fields, provides default values for objects * in older serial versions, and initializes non-serializable fields. ! * If {@code serialVersionOnStream} ! * is less than 1, initializes {@code monetarySeparator} to be ! * the same as {@code decimalSeparator} and {@code exponential} * to be 'E'. ! * 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) throws IOException, ClassNotFoundException { stream.defaultReadObject();
*** 733,742 **** --- 867,893 ---- } if (serialVersionOnStream < 3) { // 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) { try { currency = Currency.getInstance(intlCurrencySymbol);
*** 860,871 **** /** * The string used to separate the mantissa from the exponent. * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4. * <p> ! * If both <code>exponential</code> and <code>exponentialSeparator</code> ! * exist, this <code>exponentialSeparator</code> has the precedence. * * @serial * @since 1.6 */ private String exponentialSeparator; // Field new in JDK 1.6 --- 1011,1022 ---- /** * The string used to separate the mantissa from the exponent. * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4. * <p> ! * If both {@code exponential} and {@code exponentialSeparator} ! * exist, this {@code exponentialSeparator} has the precedence. * * @serial * @since 1.6 */ private String exponentialSeparator; // Field new in JDK 1.6
*** 876,885 **** --- 1027,1069 ---- * @serial * @since 1.4 */ 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; // Proclaim JDK 1.1 FCS compatibility
*** 889,915 **** // - 0 (default) for version up to JDK 1.1.5 // - 1 for version from JDK 1.1.6, which includes two new fields: // 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; /** ! * Describes the version of <code>DecimalFormatSymbols</code> present on the stream. * Possible values are: * <ul> * <li><b>0</b> (or uninitialized): versions prior to JDK 1.1.6. * * <li><b>1</b>: Versions written by JDK 1.1.6 or later, which include ! * two new fields: <code>monetarySeparator</code> and <code>exponential</code>. * <li><b>2</b>: Versions written by J2SE 1.4 or later, which include a ! * new <code>locale</code> field. * <li><b>3</b>: Versions written by J2SE 1.6 or later, which include a ! * new <code>exponentialSeparator</code> field. * </ul> ! * When streaming out a <code>DecimalFormatSymbols</code>, the most recent format ! * (corresponding to the highest allowable <code>serialVersionOnStream</code>) * is always written. * * @serial * @since 1.1.6 */ --- 1073,1104 ---- // - 0 (default) for version up to JDK 1.1.5 // - 1 for version from JDK 1.1.6, which includes two new fields: // 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. ! // - 4 for version from Java SE 13, which includes perMillText, percentText, ! // and minusSignText field. ! private static final int currentSerialVersion = 4; /** ! * Describes the version of {@code DecimalFormatSymbols} present on the stream. * Possible values are: * <ul> * <li><b>0</b> (or uninitialized): versions prior to JDK 1.1.6. * * <li><b>1</b>: Versions written by JDK 1.1.6 or later, which include ! * two new fields: {@code monetarySeparator} and {@code exponential}. * <li><b>2</b>: Versions written by J2SE 1.4 or later, which include a ! * new {@code locale} field. * <li><b>3</b>: Versions written by J2SE 1.6 or later, which include a ! * new {@code exponentialSeparator} field. ! * <li><b>4</b>: Versions written by Java SE 13 or later, which include ! * new {@code perMillText}, {@code percentText}, and ! * {@code minusSignText} field. * </ul> ! * When streaming out a {@code DecimalFormatSymbols}, the most recent format ! * (corresponding to the highest allowable {@code serialVersionOnStream}) * is always written. * * @serial * @since 1.1.6 */
< prev index next >