JSR-354 MonetaryAmountFormat не работает в двух направлениях для других символов валюты, кроме $, € или £

Вот пример кода, который я использую с Moneta версии 1.1:

    Locale LANG = Locale.CHINA;  // also tried new Locale("pl", "PL");

    final MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(
            AmountFormatQueryBuilder.of(LANG)
                    .set(CurrencyStyle.SYMBOL)
                    .set("pattern", "#,##0.00### ¤")
                    .build()
    );
    final String formatted = format.format(Money.of(new BigDecimal("1234.56"), Monetary.getCurrency(LANG)));

    System.out.println(formatted);

    System.out.println(format.parse(formatted).getNumber());

Это должно работать, так как я конвертирую один и тот же объект туда и обратно. Если я не ошибся, и конвертер не является двусторонним для других валют, кроме $, € или £.

Последняя строка вылетает с:

Exception in thread "main" java.lang.IllegalArgumentException: Invalid error index > input.length
at javax.money.format.MonetaryParseException.<init>(MonetaryParseException.java:56)
at org.javamoney.moneta.internal.format.AmountNumberToken.parse(AmountNumberToken.java:140)
at org.javamoney.moneta.internal.format.DefaultMonetaryAmountFormat.parse(DefaultMonetaryAmountFormat.java:190)
at test.main(test.java:27)

Это происходит, если предоставленная локаль не связана с одним из $, € или £. Например, этот код будет работать для Locale.US, но вылетит для Locale.CHINA, а также для new Locale("pl", "PL"). Так что это проблема не только с пользовательскими Locale, но и со статически предопределенными.

Я немного покопался во внутреннем пакете и нашел org.javamoney.moneta.internal.format.CurrencyToken.parse(CurrencyToken.java:196), который выглядит так:

case SYMBOL:
    if (token.startsWith("$")) {
        cur = Monetary.getCurrency("USD");
        context.consume("$");
    } else if (token.startsWith("€")) {
        cur = Monetary.getCurrency("EUR");
        context.consume("€");
    } else if (token.startsWith("£")) {
        cur = Monetary.getCurrency("GBP");
        context.consume("£");
    } else {
        cur = Monetary.getCurrency(token);
        context.consume(token);
    }
    context.setParsedCurrency(cur);
    break;

Есть ли способ заставить мой код работать с валютами, отличными от $, € или £?


Я попробовал еще несколько вещей, например, при условии, что Locale.CANADA у них также есть символ $ в качестве символа валюты, поэтому он выполняется без сбоев, но возвращает неверные данные.

    Locale LANG = Locale.CANADA;

    final MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(
            AmountFormatQueryBuilder.of(LANG)
                    .set(CurrencyStyle.SYMBOL)
                    .set("pattern", "#,##0.00### ¤")
                    .build()
    );
    final String formatted = format.format(Money.of(new BigDecimal("1234.56"), Monetary.getCurrency(LANG)));

    System.out.println(formatted);

    System.out.println(format.parse(formatted).getCurrency().getCurrencyCode());

последняя строка возвращает USD вместо CAD, что делает этот if-else для $. Я думаю, что это также ошибочно предполагает, что символ-валюта является отображением один к одному.


person abc    schedule 25.10.2016    source источник


Ответы (1)


Мы работаем над решением, возникли проблемы https://github.com/JavaMoney/jsr354-ri/issues/149.

Ожидайте патчи Moneta для этой и других проблем в ближайшее время.

Вернер

person Werner Keil    schedule 08.02.2017