JavaMoney / jsr354-ri

JSR 354 - Moneta: Reference Implementation
Other
344 stars 101 forks source link

Currency code parsing broken for everything but € and £ #274

Closed marschall closed 5 years ago

marschall commented 5 years ago

I recently stumbled over the SYMBOL branch in org.javamoney.moneta.internal.format.CurrencyToken.parse(ParseContext).

I believe this is broken for everything but € and £. It uses javax.money.Monetary.getCurrency(String, String...) as a fallback but passes a currency symbol as an ISO currency code argument, which will never work. Also there are a lot more currency symbols besides $ that are ambiguous, see https://en.wikipedia.org/wiki/Currency_symbol.

To illustrate consider the following test for Indian rupees which fails:


    /**
     * Test related to parsing currency symbols.
     */
    @Test
    public void testParseCurrencySymbol() {
        MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(
                    AmountFormatQueryBuilder.of(Locale.GERMANY)
                        .set(CurrencyStyle.SYMBOL)
                        .build());
        Money money = Money.of(new BigDecimal("1234567.89"), "EUR");
        String expectedFormattedString = "1.234.567,89 €";
        assertEquals(expectedFormattedString, format.format(money));
        assertEquals(money, Money.parse(expectedFormattedString, format));

        money = Money.of(new BigDecimal("1234567.89"), "INR");
        expectedFormattedString = "1.234.567,89 ₹";
        assertEquals(expectedFormattedString, format.format(money));
        assertEquals(money, Money.parse(expectedFormattedString, format));
    }
stokito commented 5 years ago

Yes, this also should be implemented. Even more: we can easily solve ambiguous by locale. For example if locale was set to HK (Honk Kong) then the $ sign means HKD (Honk Kong Dollar)

marschall commented 5 years ago

Even more: we can easily solve ambiguous by locale. For example if locale was set to HK (Honk Kong) then the $ sign means HKD (Honk Kong Dollar)

I don't think we can make that assumption. AFAIK the locale just affects the parsing and formatting not the actual currency. If you have a multi currency application in Hong Kong it may display any currency formatted according to local display rules not just Honk Kong Dollar.

keilw commented 5 years ago

It doesn't affect the language either, take Switzerland or many other countries with multiple languages even official ones. There is however an official currency, so similar to the BG example we can make those assumptions where necessary.

keilw commented 5 years ago

Thanks to IntelliJ (Eclipse recently is no longer compatible with TestNG 👎 ) Debugging I was able to pinpoint a major part of the problem. For every currency symbol but $, € or £ the Monetary.getCurrency() method applied throws an exception: UnknownCurrencyException [currencyCode=₹] It tries to accidentally use the SYMBOL as CODE or the symbol really doesn't work in the underlying system, could be something with the Locale.

keilw commented 5 years ago

It can be fixed in Moneta, but the BP has a totally different behavior in Unit tests, so I don't see the need to fix this very special corner case any more. For a new version we should think about improving CurrencyQuery which does not accept a SYMBOL right now, nor does CurrencyToken support a numeric code right now either.

keilw commented 5 years ago

@stokito Actually HKD won't work, the CurrencyToken has a special exception case for "$" but Rupees or Yen and a few other currencies with unique symbols in the JDK will work now. @marschall Please both have a look, if you could add some more tests to MonetaryFormatsParseBySymbolTest it would be appreciated.

marschall commented 5 years ago

@keilw I had a quick look, here are my first impressions

should I open a review?

keilw commented 5 years ago

@marschall I'm afraid for the MR1 this may have to do, because the source of all other currency symbols is totally unclear. We may have to tap into the Unicode CLDR beyond what Java SE makes use of it. If you would like to propose a PR for the last 3 bullet points, please go ahead.

marschall commented 5 years ago

@keilw I don't think this needs to be solved in MR1 of JSR-354. org.javamoney.moneta.format#CurrencyStyle is a Moneta extension, not part of JSR-354. Therefore this can be solved in Moneta without affecting MR1. So Moneta can just define under what property in the MonetaryContext it expects the currency symobl. MonetaryContext is intended for provider specific extensions like the symbol. What about things like "1.234.567,89 NOK" parsing with CurrencyStyle.SYMBOL? Should I create a bug for this?

keilw commented 5 years ago

Feel free, but please note, we must not squeeze all of that into the MR1. It should be out ASAP mostly to fix the long overdue license issue we were left to solve only after the Maintenance Lead Transfer. If you feel something can be done in a 1.5 or 1.6 update to Moneta after the MR, sure, why not, but there should be no changes in the API, especially something like CurrencyQuery.getCurrencySymbols() which does not exist at this point.