0

Recently Sun/Oracle changed currency code for Ukrainian hrivna to incorrect one and I've to fix that in my code.

I find out that Java 6 should allows me to do that at Java level (details are here) via CurrencyNameProvider (see also).

Unfortunately I don't understand which locales should return method

public Locale[] getAvailableLocales() {}

Any working examples are welcome!

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
FoxyBOA
  • 5,788
  • 8
  • 48
  • 82
  • Just in case, the bug I intended to fix was corrected in Java 6 update 25. Details are here (in Russian) http://foxyboa.blogspot.com/2011/05/java-oracle.html – FoxyBOA May 05 '11 at 13:09

2 Answers2

2
// Be aware that you need to provide ukrainian names to ALL currency symbols which
// your program uses.

import java.util.Locale;
import java.util.spi.CurrencyNameProvider;

public class UaCurrencyNameProvider extends CurrencyNameProvider {

    private static final Locale UKRAINE = new Locale("uk", "UA");
    private static final String UAH_SYMB = "грн.";
    private Locale[] availableLocales = new Locale[] {UKRAINE};

    @Override
    public Locale[] getAvailableLocales() {
        return availableLocales;
    }

    @Override
    public String getSymbol(String currencyCode, Locale locale) {
        if(currencyCode == null) {
            throw new NullPointerException();
        }
        else if(!UKRAINE.equals(locale)) {
            throw new IllegalArgumentException("Locale not supported");
        }
        else if("UAH".equals(currencyCode)) {
            return UAH_SYMB;
        } else {
            return null;
        }
    }
}
Nulldevice
  • 3,926
  • 3
  • 31
  • 37
  • Possible, I'm missing something, but Currency uah = Currency.getInstance("UAH"); System.out.println(uah.getSymbol()); still return "грл." – FoxyBOA Apr 30 '11 at 16:44
  • From the ApiDoc; `If no symbol can be determined, null should be returned`, so your implementation of `getSymbol(String currencyCode, Locale locale)` must return `null` instead of throwing an IllegalArgumentException. – Michael Konietzka Apr 30 '11 at 16:52
  • @FoxyBOA: Did you provide required information at META-INF/services as described here: http://download.oracle.com/javase/6/docs/api/java/util/spi/LocaleServiceProvider.html ? – Nulldevice Apr 30 '11 at 16:54
  • @Michael Konietzka: as far as I know (I am from Russia), our neighbours use "грн." as currency symbol - at least that is what I see in e-commerse, financial news, books, etc. – Nulldevice Apr 30 '11 at 16:57
  • @Michael Konietzka: thank you for a pointing a flaw - I will update my answer. – Nulldevice Apr 30 '11 at 17:01
  • Ok, now I see the difference between `грн.` vs `грв.` (I am from germany). I thought that @FoxyBOA wanted to use the new sign `₴` as currency symbol, but he wanted `грн.` – Michael Konietzka Apr 30 '11 at 17:09
  • @Nulldevice, yes I packed the class to separate jar file, add appropriate info to META-INF\services\java.util.spi.CurrencyNameProvider, put the jar to exts lib. I even see that getAvailableLocales() is calling, but getSymbol() is never calling (why - have no idea) – FoxyBOA Apr 30 '11 at 17:38
  • @FoxyBOA: It is not clear which locale you use when calling getSymbol() - without parameters (Default?). Try first exact name: System.out.println(uah.getSymbol(new Locale("uk", "UA"))); I managed to make it work with a precise specification of locale. – Nulldevice Apr 30 '11 at 18:21
  • @Nulldevice: The same result. Currency uah = Currency.getInstance("UAH"); System.out.println(uah.getSymbol(new Locale("uk", "UA"))); Output is "грл." – FoxyBOA Apr 30 '11 at 23:53
1

LocaleServiceProvider:Locale sensitive factory methods and methods for name retrieval in the java.text and java.util packages invoke service provider methods when needed to support the requested locale. The methods first check whether the Java runtime environment itself supports the requested locale, and use its support if available. Otherwise, they call the getAvailableLocales() methods of installed providers for the appropriate interface to find one that supports the requested locale.

So if the JRE has support for the requested Locale, you cannot override it with a custom provider in your extension, because the default providers will be asked first.

Example, which tries to provide a new symbol for UAH for Locale xx_YY BungaBunga and uk_UA ungarn$$$ :

public class UkCurrencyNameProvider extends CurrencyNameProvider {
private static final Locale XX_YY = new Locale("xx", "YY");
private static final Locale UK_UA = new Locale("uk", "UA");
private static final Map<Locale, String> SYMBOL_MAP;
static {
SYMBOL_MAP = new HashMap<Locale, String>();
UkCurrencyNameProvider.SYMBOL_MAP.put(UkCurrencyNameProvider.XX_YY,
        "BungaBunga");
UkCurrencyNameProvider.SYMBOL_MAP.put(UK_UA, "ungarn$$$");
}
private static final Locale[] AVAILABLE_LOCALES = UkCurrencyNameProvider.SYMBOL_MAP
        .keySet().toArray(
                new Locale[UkCurrencyNameProvider.SYMBOL_MAP.size()]);

/*
 * (non-Javadoc)
 * @see java.util.spi.CurrencyNameProvider#getSymbol(java.lang.String,
 * java.util.Locale)
 */
@Override
public String getSymbol(final String currencyCode, final Locale locale) {
    final String result;
    if ("UAH".equals(currencyCode)) {
    result = UkCurrencyNameProvider.SYMBOL_MAP.get(locale);
    } else {
    result = null;
    }
    return result;
}

/*
 * (non-Javadoc)
 * @see java.util.spi.LocaleServiceProvider#getAvailableLocales()
 */
@Override
public Locale[] getAvailableLocales() {
    return UkCurrencyNameProvider.AVAILABLE_LOCALES.clone();

}

}

The code

Locale[] test=new Locale[] {new Locale("xx","YY"),new Locale("uk","UA")};
for (Locale loc:test)
 {System.out.println(loc+": "+Currency.getInstance("UAH").getSymbol(loc));}

will output

xx_YY: BungaBunga

uk_UA: грл.

because the standard JRE knows about uk_UA and will provide its already known currency symbol грл.. For xx_YY the JRE has none information and will ask the providers in the extension. The custom provider will return BungaBunga.

Michael Konietzka
  • 5,419
  • 2
  • 28
  • 29