From: Andrew John Hughes getInstance()
methods rather than by using
+ * a constructor.
+ *
+ * @see java.util.Locale
+ * @author Guilhem Lavaux Currency
instances to
+ * ensure the singleton nature of this class. The key
+ * is the locale of the currency.
+ *
+ * @see #getInstance(java.util.Locale)
+ * @see #readResolve()
+ * @serial ignored.
+ */
+ private transient static Map cache;
+
+ /**
+ * Instantiates the cache.
+ */
+ static
+ {
+ cache = new HashMap();
+ }
+
+ /**
+ * Default constructor for deserialization
+ */
private Currency ()
{
}
+ /**
+ * Constructor to create a Currency
object
+ * for a particular Locale
.
+ * All components of the given locale, other than the
+ * country code, are ignored. The results of calling this
+ * method may vary over time, as the currency associated with
+ * a particular country changes. For countries without
+ * a given currency (e.g. Antarctica), the result is null.
+ *
+ * @param loc the locale for the new currency.
+ */
private Currency (Locale loc)
{
this.locale = loc;
this.res = ResourceBundle.getBundle ("gnu.java.locale.LocaleInformation",
locale, ClassLoader.getSystemClassLoader());
+ /* Retrieve the ISO4217 currency code */
+ try
+ {
+ currencyCode = res.getString ("intlCurrencySymbol");
+ }
+ catch (Exception _)
+ {
+ currencyCode = null;
+ }
}
/**
@@ -65,18 +151,20 @@ public final class Currency implements Serializable
*/
public String getCurrencyCode ()
{
- try
- {
- return res.getString ("intlCurrencySymbol");
- }
- catch (Exception _)
- {
- return null;
- }
+ return currencyCode;
}
/**
- * @return number of digits after decimal separator for this currency.
+ * Returns the number of digits which occur after the decimal point
+ * for this particular currency. For example, currencies such
+ * as the U.S. dollar, the Euro and the Great British pound have two
+ * digits following the decimal point to indicate the value which exists
+ * in the associated lower-valued coinage (cents in the case of the first
+ * two, pennies in the latter). Some currencies such as the Japanese
+ * Yen have no digits after the decimal point. In the case of pseudo
+ * currencies, such as IMF Special Drawing Rights, -1 is returned.
+ *
+ * @return the number of digits after the decimal separator for this currency.
*/
public int getDefaultFractionDigits ()
{
@@ -87,48 +175,87 @@ public final class Currency implements Serializable
/**
* Builds a new currency instance for this locale.
+ * All components of the given locale, other than the
+ * country code, are ignored. The results of calling this
+ * method may vary over time, as the currency associated with
+ * a particular country changes. For countries without
+ * a given currency (e.g. Antarctica), the result is null.
*
* @param locale a Locale
instance.
- *
* @return a new Currency
instance.
+ * @throws NullPointerException if the locale or its
+ * country code is null.
+ * @throws IllegalArgumentException if the country of
+ * the given locale is not a supported ISO3166 code.
*/
public static Currency getInstance (Locale locale)
{
- return new Currency (locale);
+ /**
+ * The new instance must be the only available instance
+ * for the currency it supports. We ensure this happens,
+ * while maintaining a suitable performance level, by
+ * creating the appropriate object on the first call to
+ * this method, and returning the cached instance on
+ * later calls.
+ */
+ Currency newCurrency;
+
+ /* Attempt to get the currency from the cache */
+ newCurrency = (Currency) cache.get(locale);
+ if (newCurrency == null)
+ {
+ /* Create the currency for this locale */
+ newCurrency = new Currency (locale);
+ /* Cache it */
+ cache.put(locale, newCurrency);
+ }
+ /* Return the instance */
+ return newCurrency;
}
/**
* Builds the currency corresponding to the specified currency code.
*
* @param currencyCode a string representing a currency code.
- *
* @return a new Currency
instance.
+ * @throws NullPointerException if currencyCode is null.
+ * @throws IllegalArgumentException if the supplied currency code
+ * is not a supported ISO 4217 code.
*/
public static Currency getInstance (String currencyCode)
{
- Locale[] all_locales = Locale.getAvailableLocales ();
+ Locale[] allLocales = Locale.getAvailableLocales ();
- for (int i=0;i
+ * For example, a supplied locale may specify a different symbol
+ * for the currency, due to conflicts with its own currency.
+ * This would be the case with the American currency, the dollar.
+ * Locales that also use a dollar-based currency (e.g. Canada, Australia)
+ * need to differentiate the American dollar using 'US$' rather than '$'.
+ * So, supplying one of these locales to getSymbol()
would
+ * return this value, rather than the standard '$'.
+ *
+ * In cases where there is no such symbol for a particular currency, + * the ISO 4217 currency code is returned. + *
* * @param locale the locale to express the symbol in. - * @return the currency symbol. + * @return the currency symbol, or the ISO 4217 currency code if + * one doesn't exist. + * @throws NullPointerException if the locale is null. */ public String getSymbol(Locale locale) { // TODO. The behaviour is unclear if locale != this.locale. // First we need to implement fully LocaleInformation*.java + + /* + * FIXME: My reading of how this method works has this implementation + * as wrong. It should return a value relating to how the specified + * locale handles the symbol for this currency. This implementation + * seems to just do a variation of getInstance(locale). + */ try { - ResourceBundle res = + ResourceBundle localeResource = ResourceBundle.getBundle ("gnu.java.locale.LocaleInformation", locale, Currency.class.getClassLoader()); - if (res.equals(this.res)) - return res.getString ("currencySymbol"); + if (localeResource.equals(res)) + return localeResource.getString ("currencySymbol"); else - return res.getString ("intlCurrencySymbol"); + return localeResource.getString ("intlCurrencySymbol"); } catch (Exception e1) { @@ -178,13 +331,25 @@ public final class Currency implements Serializable */ public String toString() { - try - { - return res.getString ("intlCurrencySymbol"); - } - catch (Exception _) - { - return "(unknown currency)"; - } + return getCurrencyCode(); } + + /** + * Resolves the deserialized object to the singleton instance for its + * particular currency. The currency code of the deserialized instance + * is used to return the correct instance. + * + * @return the singleton instance for the currency specified by the + * currency code of the deserialized object. This replaces + * the deserialized object as the returned object from + * deserialization. + * @throws ObjectStreamException if a problem occurs with deserializing + * the object. + */ + private Object readResolve() + throws ObjectStreamException + { + return getInstance(currencyCode); + } + }