jdk/src/share/classes/java/text/DecimalFormatSymbols.java
changeset 2 90ce3da70b43
child 5506 202f599c92aa
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 1996-2006 Sun Microsystems, Inc.  All Rights Reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 /*
       
    27  * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
       
    28  * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
       
    29  *
       
    30  *   The original version of this source code and documentation is copyrighted
       
    31  * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
       
    32  * materials are provided under terms of a License Agreement between Taligent
       
    33  * and Sun. This technology is protected by multiple US and International
       
    34  * patents. This notice and attribution to Taligent may not be removed.
       
    35  *   Taligent is a registered trademark of Taligent, Inc.
       
    36  *
       
    37  */
       
    38 
       
    39 package java.text;
       
    40 
       
    41 import java.io.IOException;
       
    42 import java.io.ObjectInputStream;
       
    43 import java.io.Serializable;
       
    44 import java.text.spi.DecimalFormatSymbolsProvider;
       
    45 import java.util.Currency;
       
    46 import java.util.Hashtable;
       
    47 import java.util.Locale;
       
    48 import java.util.ResourceBundle;
       
    49 import java.util.spi.LocaleServiceProvider;
       
    50 import sun.util.LocaleServiceProviderPool;
       
    51 import sun.util.resources.LocaleData;
       
    52 
       
    53 /**
       
    54  * This class represents the set of symbols (such as the decimal separator,
       
    55  * the grouping separator, and so on) needed by <code>DecimalFormat</code>
       
    56  * to format numbers. <code>DecimalFormat</code> creates for itself an instance of
       
    57  * <code>DecimalFormatSymbols</code> from its locale data.  If you need to change any
       
    58  * of these symbols, you can get the <code>DecimalFormatSymbols</code> object from
       
    59  * your <code>DecimalFormat</code> and modify it.
       
    60  *
       
    61  * @see          java.util.Locale
       
    62  * @see          DecimalFormat
       
    63  * @author       Mark Davis
       
    64  * @author       Alan Liu
       
    65  */
       
    66 
       
    67 public class DecimalFormatSymbols implements Cloneable, Serializable {
       
    68 
       
    69     /**
       
    70      * Create a DecimalFormatSymbols object for the default locale.
       
    71      * This constructor can only construct instances for the locales
       
    72      * supported by the Java runtime environment, not for those
       
    73      * supported by installed
       
    74      * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
       
    75      * implementations. For full locale coverage, use the
       
    76      * {@link #getInstance(Locale) getInstance} method.
       
    77      */
       
    78     public DecimalFormatSymbols() {
       
    79         initialize( Locale.getDefault() );
       
    80     }
       
    81 
       
    82     /**
       
    83      * Create a DecimalFormatSymbols object for the given locale.
       
    84      * This constructor can only construct instances for the locales
       
    85      * supported by the Java runtime environment, not for those
       
    86      * supported by installed
       
    87      * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
       
    88      * implementations. For full locale coverage, use the
       
    89      * {@link #getInstance(Locale) getInstance} method.
       
    90      *
       
    91      * @exception NullPointerException if <code>locale</code> is null
       
    92      */
       
    93     public DecimalFormatSymbols( Locale locale ) {
       
    94         initialize( locale );
       
    95     }
       
    96 
       
    97     /**
       
    98      * Returns an array of all locales for which the
       
    99      * <code>getInstance</code> methods of this class can return
       
   100      * localized instances.
       
   101      * The returned array represents the union of locales supported by the Java
       
   102      * runtime and by installed
       
   103      * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
       
   104      * implementations.  It must contain at least a <code>Locale</code>
       
   105      * instance equal to {@link java.util.Locale#US Locale.US}.
       
   106      *
       
   107      * @return An array of locales for which localized
       
   108      *         <code>DecimalFormatSymbols</code> instances are available.
       
   109      * @since 1.6
       
   110      */
       
   111     public static Locale[] getAvailableLocales() {
       
   112         LocaleServiceProviderPool pool =
       
   113             LocaleServiceProviderPool.getPool(DecimalFormatSymbolsProvider.class);
       
   114         return pool.getAvailableLocales();
       
   115     }
       
   116 
       
   117     /**
       
   118      * Gets the <code>DecimalFormatSymbols</code> instance for the default
       
   119      * locale.  This method provides access to <code>DecimalFormatSymbols</code>
       
   120      * instances for locales supported by the Java runtime itself as well
       
   121      * as for those supported by installed
       
   122      * {@link java.text.spi.DecimalFormatSymbolsProvider
       
   123      * DecimalFormatSymbolsProvider} implementations.
       
   124      * @return a <code>DecimalFormatSymbols</code> instance.
       
   125      * @since 1.6
       
   126      */
       
   127     public static final DecimalFormatSymbols getInstance() {
       
   128         return getInstance(Locale.getDefault());
       
   129     }
       
   130 
       
   131     /**
       
   132      * Gets the <code>DecimalFormatSymbols</code> instance for the specified
       
   133      * locale.  This method provides access to <code>DecimalFormatSymbols</code>
       
   134      * instances for locales supported by the Java runtime itself as well
       
   135      * as for those supported by installed
       
   136      * {@link java.text.spi.DecimalFormatSymbolsProvider
       
   137      * DecimalFormatSymbolsProvider} implementations.
       
   138      * @param locale the desired locale.
       
   139      * @return a <code>DecimalFormatSymbols</code> instance.
       
   140      * @exception NullPointerException if <code>locale</code> is null
       
   141      * @since 1.6
       
   142      */
       
   143     public static final DecimalFormatSymbols getInstance(Locale locale) {
       
   144 
       
   145         // Check whether a provider can provide an implementation that's closer
       
   146         // to the requested locale than what the Java runtime itself can provide.
       
   147         LocaleServiceProviderPool pool =
       
   148             LocaleServiceProviderPool.getPool(DecimalFormatSymbolsProvider.class);
       
   149         if (pool.hasProviders()) {
       
   150             DecimalFormatSymbols providersInstance = pool.getLocalizedObject(
       
   151                                 DecimalFormatSymbolsGetter.INSTANCE, locale);
       
   152             if (providersInstance != null) {
       
   153                 return providersInstance;
       
   154             }
       
   155         }
       
   156 
       
   157         return new DecimalFormatSymbols(locale);
       
   158     }
       
   159 
       
   160     /**
       
   161      * Gets the character used for zero. Different for Arabic, etc.
       
   162      */
       
   163     public char getZeroDigit() {
       
   164         return zeroDigit;
       
   165     }
       
   166 
       
   167     /**
       
   168      * Sets the character used for zero. Different for Arabic, etc.
       
   169      */
       
   170     public void setZeroDigit(char zeroDigit) {
       
   171         this.zeroDigit = zeroDigit;
       
   172     }
       
   173 
       
   174     /**
       
   175      * Gets the character used for thousands separator. Different for French, etc.
       
   176      */
       
   177     public char getGroupingSeparator() {
       
   178         return groupingSeparator;
       
   179     }
       
   180 
       
   181     /**
       
   182      * Sets the character used for thousands separator. Different for French, etc.
       
   183      */
       
   184     public void setGroupingSeparator(char groupingSeparator) {
       
   185         this.groupingSeparator = groupingSeparator;
       
   186     }
       
   187 
       
   188     /**
       
   189      * Gets the character used for decimal sign. Different for French, etc.
       
   190      */
       
   191     public char getDecimalSeparator() {
       
   192         return decimalSeparator;
       
   193     }
       
   194 
       
   195     /**
       
   196      * Sets the character used for decimal sign. Different for French, etc.
       
   197      */
       
   198     public void setDecimalSeparator(char decimalSeparator) {
       
   199         this.decimalSeparator = decimalSeparator;
       
   200     }
       
   201 
       
   202     /**
       
   203      * Gets the character used for per mille sign. Different for Arabic, etc.
       
   204      */
       
   205     public char getPerMill() {
       
   206         return perMill;
       
   207     }
       
   208 
       
   209     /**
       
   210      * Sets the character used for per mille sign. Different for Arabic, etc.
       
   211      */
       
   212     public void setPerMill(char perMill) {
       
   213         this.perMill = perMill;
       
   214     }
       
   215 
       
   216     /**
       
   217      * Gets the character used for percent sign. Different for Arabic, etc.
       
   218      */
       
   219     public char getPercent() {
       
   220         return percent;
       
   221     }
       
   222 
       
   223     /**
       
   224      * Sets the character used for percent sign. Different for Arabic, etc.
       
   225      */
       
   226     public void setPercent(char percent) {
       
   227         this.percent = percent;
       
   228     }
       
   229 
       
   230     /**
       
   231      * Gets the character used for a digit in a pattern.
       
   232      */
       
   233     public char getDigit() {
       
   234         return digit;
       
   235     }
       
   236 
       
   237     /**
       
   238      * Sets the character used for a digit in a pattern.
       
   239      */
       
   240     public void setDigit(char digit) {
       
   241         this.digit = digit;
       
   242     }
       
   243 
       
   244     /**
       
   245      * Gets the character used to separate positive and negative subpatterns
       
   246      * in a pattern.
       
   247      */
       
   248     public char getPatternSeparator() {
       
   249         return patternSeparator;
       
   250     }
       
   251 
       
   252     /**
       
   253      * Sets the character used to separate positive and negative subpatterns
       
   254      * in a pattern.
       
   255      */
       
   256     public void setPatternSeparator(char patternSeparator) {
       
   257         this.patternSeparator = patternSeparator;
       
   258     }
       
   259 
       
   260     /**
       
   261      * Gets the string used to represent infinity. Almost always left
       
   262      * unchanged.
       
   263      */
       
   264     public String getInfinity() {
       
   265         return infinity;
       
   266     }
       
   267 
       
   268     /**
       
   269      * Sets the string used to represent infinity. Almost always left
       
   270      * unchanged.
       
   271      */
       
   272     public void setInfinity(String infinity) {
       
   273         this.infinity = infinity;
       
   274     }
       
   275 
       
   276     /**
       
   277      * Gets the string used to represent "not a number". Almost always left
       
   278      * unchanged.
       
   279      */
       
   280     public String getNaN() {
       
   281         return NaN;
       
   282     }
       
   283 
       
   284     /**
       
   285      * Sets the string used to represent "not a number". Almost always left
       
   286      * unchanged.
       
   287      */
       
   288     public void setNaN(String NaN) {
       
   289         this.NaN = NaN;
       
   290     }
       
   291 
       
   292     /**
       
   293      * Gets the character used to represent minus sign. If no explicit
       
   294      * negative format is specified, one is formed by prefixing
       
   295      * minusSign to the positive format.
       
   296      */
       
   297     public char getMinusSign() {
       
   298         return minusSign;
       
   299     }
       
   300 
       
   301     /**
       
   302      * Sets the character used to represent minus sign. If no explicit
       
   303      * negative format is specified, one is formed by prefixing
       
   304      * minusSign to the positive format.
       
   305      */
       
   306     public void setMinusSign(char minusSign) {
       
   307         this.minusSign = minusSign;
       
   308     }
       
   309 
       
   310     /**
       
   311      * Returns the currency symbol for the currency of these
       
   312      * DecimalFormatSymbols in their locale.
       
   313      * @since 1.2
       
   314      */
       
   315     public String getCurrencySymbol()
       
   316     {
       
   317         return currencySymbol;
       
   318     }
       
   319 
       
   320     /**
       
   321      * Sets the currency symbol for the currency of these
       
   322      * DecimalFormatSymbols in their locale.
       
   323      * @since 1.2
       
   324      */
       
   325     public void setCurrencySymbol(String currency)
       
   326     {
       
   327         currencySymbol = currency;
       
   328     }
       
   329 
       
   330     /**
       
   331      * Returns the ISO 4217 currency code of the currency of these
       
   332      * DecimalFormatSymbols.
       
   333      * @since 1.2
       
   334      */
       
   335     public String getInternationalCurrencySymbol()
       
   336     {
       
   337         return intlCurrencySymbol;
       
   338     }
       
   339 
       
   340     /**
       
   341      * Sets the ISO 4217 currency code of the currency of these
       
   342      * DecimalFormatSymbols.
       
   343      * If the currency code is valid (as defined by
       
   344      * {@link java.util.Currency#getInstance(java.lang.String) Currency.getInstance}),
       
   345      * this also sets the currency attribute to the corresponding Currency
       
   346      * instance and the currency symbol attribute to the currency's symbol
       
   347      * in the DecimalFormatSymbols' locale. If the currency code is not valid,
       
   348      * then the currency attribute is set to null and the currency symbol
       
   349      * attribute is not modified.
       
   350      *
       
   351      * @see #setCurrency
       
   352      * @see #setCurrencySymbol
       
   353      * @since 1.2
       
   354      */
       
   355     public void setInternationalCurrencySymbol(String currencyCode)
       
   356     {
       
   357         intlCurrencySymbol = currencyCode;
       
   358         currency = null;
       
   359         if (currencyCode != null) {
       
   360             try {
       
   361                 currency = Currency.getInstance(currencyCode);
       
   362                 currencySymbol = currency.getSymbol();
       
   363             } catch (IllegalArgumentException e) {
       
   364             }
       
   365         }
       
   366     }
       
   367 
       
   368     /**
       
   369      * Gets the currency of these DecimalFormatSymbols. May be null if the
       
   370      * currency symbol attribute was previously set to a value that's not
       
   371      * a valid ISO 4217 currency code.
       
   372      *
       
   373      * @return the currency used, or null
       
   374      * @since 1.4
       
   375      */
       
   376     public Currency getCurrency() {
       
   377         return currency;
       
   378     }
       
   379 
       
   380     /**
       
   381      * Sets the currency of these DecimalFormatSymbols.
       
   382      * This also sets the currency symbol attribute to the currency's symbol
       
   383      * in the DecimalFormatSymbols' locale, and the international currency
       
   384      * symbol attribute to the currency's ISO 4217 currency code.
       
   385      *
       
   386      * @param currency the new currency to be used
       
   387      * @exception NullPointerException if <code>currency</code> is null
       
   388      * @since 1.4
       
   389      * @see #setCurrencySymbol
       
   390      * @see #setInternationalCurrencySymbol
       
   391      */
       
   392     public void setCurrency(Currency currency) {
       
   393         if (currency == null) {
       
   394             throw new NullPointerException();
       
   395         }
       
   396         this.currency = currency;
       
   397         intlCurrencySymbol = currency.getCurrencyCode();
       
   398         currencySymbol = currency.getSymbol(locale);
       
   399     }
       
   400 
       
   401 
       
   402     /**
       
   403      * Returns the monetary decimal separator.
       
   404      * @since 1.2
       
   405      */
       
   406     public char getMonetaryDecimalSeparator()
       
   407     {
       
   408         return monetarySeparator;
       
   409     }
       
   410 
       
   411     /**
       
   412      * Sets the monetary decimal separator.
       
   413      * @since 1.2
       
   414      */
       
   415     public void setMonetaryDecimalSeparator(char sep)
       
   416     {
       
   417         monetarySeparator = sep;
       
   418     }
       
   419 
       
   420     //------------------------------------------------------------
       
   421     // BEGIN   Package Private methods ... to be made public later
       
   422     //------------------------------------------------------------
       
   423 
       
   424     /**
       
   425      * Returns the character used to separate the mantissa from the exponent.
       
   426      */
       
   427     char getExponentialSymbol()
       
   428     {
       
   429         return exponential;
       
   430     }
       
   431   /**
       
   432    * Returns the string used to separate the mantissa from the exponent.
       
   433    * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
       
   434    *
       
   435    * @return the exponent separator string
       
   436    * @see #setExponentSeparator(java.lang.String)
       
   437    * @since 1.6
       
   438    */
       
   439     public String getExponentSeparator()
       
   440     {
       
   441         return exponentialSeparator;
       
   442     }
       
   443 
       
   444     /**
       
   445      * Sets the character used to separate the mantissa from the exponent.
       
   446      */
       
   447     void setExponentialSymbol(char exp)
       
   448     {
       
   449         exponential = exp;
       
   450     }
       
   451 
       
   452   /**
       
   453    * Sets the string used to separate the mantissa from the exponent.
       
   454    * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
       
   455    *
       
   456    * @param exp the exponent separator string
       
   457    * @exception NullPointerException if <code>exp</code> is null
       
   458    * @see #getExponentSeparator()
       
   459    * @since 1.6
       
   460    */
       
   461     public void setExponentSeparator(String exp)
       
   462     {
       
   463         if (exp == null) {
       
   464             throw new NullPointerException();
       
   465         }
       
   466         exponentialSeparator = exp;
       
   467      }
       
   468 
       
   469 
       
   470     //------------------------------------------------------------
       
   471     // END     Package Private methods ... to be made public later
       
   472     //------------------------------------------------------------
       
   473 
       
   474     /**
       
   475      * Standard override.
       
   476      */
       
   477     public Object clone() {
       
   478         try {
       
   479             return (DecimalFormatSymbols)super.clone();
       
   480             // other fields are bit-copied
       
   481         } catch (CloneNotSupportedException e) {
       
   482             throw new InternalError();
       
   483         }
       
   484     }
       
   485 
       
   486     /**
       
   487      * Override equals.
       
   488      */
       
   489     public boolean equals(Object obj) {
       
   490         if (obj == null) return false;
       
   491         if (this == obj) return true;
       
   492         if (getClass() != obj.getClass()) return false;
       
   493         DecimalFormatSymbols other = (DecimalFormatSymbols) obj;
       
   494         return (zeroDigit == other.zeroDigit &&
       
   495         groupingSeparator == other.groupingSeparator &&
       
   496         decimalSeparator == other.decimalSeparator &&
       
   497         percent == other.percent &&
       
   498         perMill == other.perMill &&
       
   499         digit == other.digit &&
       
   500         minusSign == other.minusSign &&
       
   501         patternSeparator == other.patternSeparator &&
       
   502         infinity.equals(other.infinity) &&
       
   503         NaN.equals(other.NaN) &&
       
   504         currencySymbol.equals(other.currencySymbol) &&
       
   505         intlCurrencySymbol.equals(other.intlCurrencySymbol) &&
       
   506         currency == other.currency &&
       
   507         monetarySeparator == other.monetarySeparator &&
       
   508         exponentialSeparator.equals(other.exponentialSeparator) &&
       
   509         locale.equals(other.locale));
       
   510     }
       
   511 
       
   512     /**
       
   513      * Override hashCode.
       
   514      */
       
   515     public int hashCode() {
       
   516             int result = zeroDigit;
       
   517             result = result * 37 + groupingSeparator;
       
   518             result = result * 37 + decimalSeparator;
       
   519             return result;
       
   520     }
       
   521 
       
   522     /**
       
   523      * Initializes the symbols from the FormatData resource bundle.
       
   524      */
       
   525     private void initialize( Locale locale ) {
       
   526         this.locale = locale;
       
   527 
       
   528         // get resource bundle data - try the cache first
       
   529         boolean needCacheUpdate = false;
       
   530         Object[] data = (Object[]) cachedLocaleData.get(locale);
       
   531         if (data == null) {  /* cache miss */
       
   532             data = new Object[3];
       
   533             ResourceBundle rb = LocaleData.getNumberFormatData(locale);
       
   534             data[0] = rb.getStringArray("NumberElements");
       
   535             needCacheUpdate = true;
       
   536         }
       
   537 
       
   538         String[] numberElements = (String[]) data[0];
       
   539 
       
   540         decimalSeparator = numberElements[0].charAt(0);
       
   541         groupingSeparator = numberElements[1].charAt(0);
       
   542         patternSeparator = numberElements[2].charAt(0);
       
   543         percent = numberElements[3].charAt(0);
       
   544         zeroDigit = numberElements[4].charAt(0); //different for Arabic,etc.
       
   545         digit = numberElements[5].charAt(0);
       
   546         minusSign = numberElements[6].charAt(0);
       
   547         exponential = numberElements[7].charAt(0);
       
   548         exponentialSeparator = numberElements[7]; //string representation new since 1.6
       
   549         perMill = numberElements[8].charAt(0);
       
   550         infinity  = numberElements[9];
       
   551         NaN = numberElements[10];
       
   552 
       
   553         // Try to obtain the currency used in the locale's country.
       
   554         // Check for empty country string separately because it's a valid
       
   555         // country ID for Locale (and used for the C locale), but not a valid
       
   556         // ISO 3166 country code, and exceptions are expensive.
       
   557         if (!"".equals(locale.getCountry())) {
       
   558             try {
       
   559                 currency = Currency.getInstance(locale);
       
   560             } catch (IllegalArgumentException e) {
       
   561                 // use default values below for compatibility
       
   562             }
       
   563         }
       
   564         if (currency != null) {
       
   565             intlCurrencySymbol = currency.getCurrencyCode();
       
   566             if (data[1] != null && data[1] == intlCurrencySymbol) {
       
   567                 currencySymbol = (String) data[2];
       
   568             } else {
       
   569                 currencySymbol = currency.getSymbol(locale);
       
   570                 data[1] = intlCurrencySymbol;
       
   571                 data[2] = currencySymbol;
       
   572                 needCacheUpdate = true;
       
   573             }
       
   574         } else {
       
   575             // default values
       
   576             intlCurrencySymbol = "XXX";
       
   577             try {
       
   578                 currency = Currency.getInstance(intlCurrencySymbol);
       
   579             } catch (IllegalArgumentException e) {
       
   580             }
       
   581             currencySymbol = "\u00A4";
       
   582         }
       
   583         // Currently the monetary decimal separator is the same as the
       
   584         // standard decimal separator for all locales that we support.
       
   585         // If that changes, add a new entry to NumberElements.
       
   586         monetarySeparator = decimalSeparator;
       
   587 
       
   588         if (needCacheUpdate) {
       
   589             cachedLocaleData.put(locale, data);
       
   590         }
       
   591     }
       
   592 
       
   593     /**
       
   594      * Reads the default serializable fields, provides default values for objects
       
   595      * in older serial versions, and initializes non-serializable fields.
       
   596      * If <code>serialVersionOnStream</code>
       
   597      * is less than 1, initializes <code>monetarySeparator</code> to be
       
   598      * the same as <code>decimalSeparator</code> and <code>exponential</code>
       
   599      * to be 'E'.
       
   600      * If <code>serialVersionOnStream</code> is less than 2,
       
   601      * initializes <code>locale</code>to the root locale, and initializes
       
   602      * If <code>serialVersionOnStream</code> is less than 3, it initializes
       
   603      * <code>exponentialSeparator</code> using <code>exponential</code>.
       
   604      * Sets <code>serialVersionOnStream</code> back to the maximum allowed value so that
       
   605      * default serialization will work properly if this object is streamed out again.
       
   606      * Initializes the currency from the intlCurrencySymbol field.
       
   607      *
       
   608      * @since JDK 1.1.6
       
   609      */
       
   610     private void readObject(ObjectInputStream stream)
       
   611             throws IOException, ClassNotFoundException {
       
   612         stream.defaultReadObject();
       
   613         if (serialVersionOnStream < 1) {
       
   614             // Didn't have monetarySeparator or exponential field;
       
   615             // use defaults.
       
   616             monetarySeparator = decimalSeparator;
       
   617             exponential       = 'E';
       
   618         }
       
   619         if (serialVersionOnStream < 2) {
       
   620             // didn't have locale; use root locale
       
   621             locale = Locale.ROOT;
       
   622         }
       
   623         if (serialVersionOnStream < 3) {
       
   624             // didn't have exponentialSeparator. Create one using exponential
       
   625             exponentialSeparator = Character.toString(exponential);
       
   626         }
       
   627         serialVersionOnStream = currentSerialVersion;
       
   628 
       
   629         if (intlCurrencySymbol != null) {
       
   630             try {
       
   631                  currency = Currency.getInstance(intlCurrencySymbol);
       
   632             } catch (IllegalArgumentException e) {
       
   633             }
       
   634         }
       
   635     }
       
   636 
       
   637     /**
       
   638      * Character used for zero.
       
   639      *
       
   640      * @serial
       
   641      * @see #getZeroDigit
       
   642      */
       
   643     private  char    zeroDigit;
       
   644 
       
   645     /**
       
   646      * Character used for thousands separator.
       
   647      *
       
   648      * @serial
       
   649      * @see #getGroupingSeparator
       
   650      */
       
   651     private  char    groupingSeparator;
       
   652 
       
   653     /**
       
   654      * Character used for decimal sign.
       
   655      *
       
   656      * @serial
       
   657      * @see #getDecimalSeparator
       
   658      */
       
   659     private  char    decimalSeparator;
       
   660 
       
   661     /**
       
   662      * Character used for per mille sign.
       
   663      *
       
   664      * @serial
       
   665      * @see #getPerMill
       
   666      */
       
   667     private  char    perMill;
       
   668 
       
   669     /**
       
   670      * Character used for percent sign.
       
   671      * @serial
       
   672      * @see #getPercent
       
   673      */
       
   674     private  char    percent;
       
   675 
       
   676     /**
       
   677      * Character used for a digit in a pattern.
       
   678      *
       
   679      * @serial
       
   680      * @see #getDigit
       
   681      */
       
   682     private  char    digit;
       
   683 
       
   684     /**
       
   685      * Character used to separate positive and negative subpatterns
       
   686      * in a pattern.
       
   687      *
       
   688      * @serial
       
   689      * @see #getPatternSeparator
       
   690      */
       
   691     private  char    patternSeparator;
       
   692 
       
   693     /**
       
   694      * String used to represent infinity.
       
   695      * @serial
       
   696      * @see #getInfinity
       
   697      */
       
   698     private  String  infinity;
       
   699 
       
   700     /**
       
   701      * String used to represent "not a number".
       
   702      * @serial
       
   703      * @see #getNaN
       
   704      */
       
   705     private  String  NaN;
       
   706 
       
   707     /**
       
   708      * Character used to represent minus sign.
       
   709      * @serial
       
   710      * @see #getMinusSign
       
   711      */
       
   712     private  char    minusSign;
       
   713 
       
   714     /**
       
   715      * String denoting the local currency, e.g. "$".
       
   716      * @serial
       
   717      * @see #getCurrencySymbol
       
   718      */
       
   719     private  String  currencySymbol;
       
   720 
       
   721     /**
       
   722      * ISO 4217 currency code denoting the local currency, e.g. "USD".
       
   723      * @serial
       
   724      * @see #getInternationalCurrencySymbol
       
   725      */
       
   726     private  String  intlCurrencySymbol;
       
   727 
       
   728     /**
       
   729      * The decimal separator used when formatting currency values.
       
   730      * @serial
       
   731      * @since JDK 1.1.6
       
   732      * @see #getMonetaryDecimalSeparator
       
   733      */
       
   734     private  char    monetarySeparator; // Field new in JDK 1.1.6
       
   735 
       
   736     /**
       
   737      * The character used to distinguish the exponent in a number formatted
       
   738      * in exponential notation, e.g. 'E' for a number such as "1.23E45".
       
   739      * <p>
       
   740      * Note that the public API provides no way to set this field,
       
   741      * even though it is supported by the implementation and the stream format.
       
   742      * The intent is that this will be added to the API in the future.
       
   743      *
       
   744      * @serial
       
   745      * @since JDK 1.1.6
       
   746      */
       
   747     private  char    exponential;       // Field new in JDK 1.1.6
       
   748 
       
   749   /**
       
   750    * The string used to separate the mantissa from the exponent.
       
   751    * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
       
   752    * <p>
       
   753    * If both <code>exponential</code> and <code>exponentialSeparator</code>
       
   754    * exist, this <code>exponentialSeparator</code> has the precedence.
       
   755    *
       
   756    * @serial
       
   757    * @since 1.6
       
   758    */
       
   759     private  String    exponentialSeparator;       // Field new in JDK 1.6
       
   760 
       
   761     /**
       
   762      * The locale of these currency format symbols.
       
   763      *
       
   764      * @serial
       
   765      * @since 1.4
       
   766      */
       
   767     private Locale locale;
       
   768 
       
   769     // currency; only the ISO code is serialized.
       
   770     private transient Currency currency;
       
   771 
       
   772     // Proclaim JDK 1.1 FCS compatibility
       
   773     static final long serialVersionUID = 5772796243397350300L;
       
   774 
       
   775     // The internal serial version which says which version was written
       
   776     // - 0 (default) for version up to JDK 1.1.5
       
   777     // - 1 for version from JDK 1.1.6, which includes two new fields:
       
   778     //     monetarySeparator and exponential.
       
   779     // - 2 for version from J2SE 1.4, which includes locale field.
       
   780     // - 3 for version from J2SE 1.6, which includes exponentialSeparator field.
       
   781     private static final int currentSerialVersion = 3;
       
   782 
       
   783     /**
       
   784      * Describes the version of <code>DecimalFormatSymbols</code> present on the stream.
       
   785      * Possible values are:
       
   786      * <ul>
       
   787      * <li><b>0</b> (or uninitialized): versions prior to JDK 1.1.6.
       
   788      *
       
   789      * <li><b>1</b>: Versions written by JDK 1.1.6 or later, which include
       
   790      *      two new fields: <code>monetarySeparator</code> and <code>exponential</code>.
       
   791      * <li><b>2</b>: Versions written by J2SE 1.4 or later, which include a
       
   792      *      new <code>locale</code> field.
       
   793      * <li><b>3</b>: Versions written by J2SE 1.6 or later, which include a
       
   794      *      new <code>exponentialSeparator</code> field.
       
   795      * </ul>
       
   796      * When streaming out a <code>DecimalFormatSymbols</code>, the most recent format
       
   797      * (corresponding to the highest allowable <code>serialVersionOnStream</code>)
       
   798      * is always written.
       
   799      *
       
   800      * @serial
       
   801      * @since JDK 1.1.6
       
   802      */
       
   803     private int serialVersionOnStream = currentSerialVersion;
       
   804 
       
   805     /**
       
   806      * cache to hold the NumberElements and the Currency
       
   807      * of a Locale.
       
   808      */
       
   809     private static final Hashtable cachedLocaleData = new Hashtable(3);
       
   810 
       
   811     /**
       
   812      * Obtains a DecimalFormatSymbols instance from a DecimalFormatSymbolsProvider
       
   813      * implementation.
       
   814      */
       
   815     private static class DecimalFormatSymbolsGetter
       
   816         implements LocaleServiceProviderPool.LocalizedObjectGetter<DecimalFormatSymbolsProvider,
       
   817                                                                    DecimalFormatSymbols> {
       
   818         private static final DecimalFormatSymbolsGetter INSTANCE =
       
   819             new DecimalFormatSymbolsGetter();
       
   820 
       
   821         public DecimalFormatSymbols getObject(
       
   822                                 DecimalFormatSymbolsProvider decimalFormatSymbolsProvider,
       
   823                                 Locale locale,
       
   824                                 String key,
       
   825                                 Object... params) {
       
   826             assert params.length == 0;
       
   827             return decimalFormatSymbolsProvider.getInstance(locale);
       
   828         }
       
   829     }
       
   830 }