Найти CurrencyUnit из ISO ** числовой ** код валюты

Я пытаюсь отформатировать сумму, используя правильные правила форматирования, учитывая числовой код валюты ISO 4217.

Например, учитывая сумму 99,99 и числовой код 840, я ожидаю получить строку "99,99 долларов США" или аналогичную.

Глядя на реализацию JSR 354, мне кажется, что мне нужно сначала найти подходящую валютную единицу. Тем не менее, я не могу составить действительный CurrencyQuery для этой цели.

Дано

CurrencyQuery query = CurrencyQueryBuilder.of().setNumericCodes(840).build();
CurrencyUnit cu = Monetary.getCurrency(query);
MonetaryAmount amount = FastMoney.of(99.99, cu);
System.out.println(MonetaryFormats.getAmountFormat(Locale.ENGLISH).format(amount));

Я получаю следующее исключение:

Exception in thread "main" javax.money.MonetaryException: Ambiguous request for CurrencyUnit: CurrencyQuery (
{Query.numericCodes=[840]}), found: [BIF, ARS, DZD, COP, CVE, CHF, HRK, IQD, LAK, XPF, DKK, BAM, ZMK, ITL, XBB, XUA, XPT, BRL, CAD, NZD, SEK, USN, XTS, IEP, SRG, STD, BHD, USS, XAF, AUD, CDF, MTL, QAR, AOA, MGA, TOP, LYD, BOV, ISK, ADP, HTG, IDR, ANG, XXX, BTN, KHR, LTL, KES, INR, MGF, OMR, BEF, EUR, BOB, JPY, XBA, AED, SOS, XPD, SKK, FKP, XBC, CRC, SCR, MYR, MZN, LVL, GYD, XDR, GHS, XCD, MDL, MRO, ZWN, LSL, PEN, ATS, XOF, AZM, BYB, TRY, SRD, TTD, IRR, NOK, BZD, TRL, BDT, KZT, CLF, SLL, USD, ETB, BSD, SDD, UYU, ESP, VEB, TMM, CUP, NAD, DOP, NPR, TJS, VND, ZWR, AMD, FRF, TWD, LUF, GNF, MOP, MKD, JMD, CZK, PTE, LBP, ZWD, RSD, FIM, AZN, SDG, GHC, THB, MMK, BBD, PLN, ROL, NGN, RON, TZS, ERN, GBP, TPE, UZS, XBD, SGD, MXV, SVC, FJD, GWP, CNY, BYR, RUB, CSD, XAG, HKD, BND, SHP, KPW, CLP, KYD, DJF, ILS, RUR, LRD, SYP, SAR, ZWL, VUV, DEM, XSU, SIT, PHP, PYG, TND, HNL, ZAR, XFO, BMD, MWK, ZMW, UGX, NLG, JOD, KWD, YER, GMD, CUC, BGL, RWF, UAH, MVR, AWG, MZM, LKR, CYP, VEF, BWP, MXN, KRW, TMT, GIP, MUR, MNT, EEK, GTQ, PKR, PAB, KGS, GRD, YUM, SZL, GEL, WST, MAD, EGP, SBD, ALL, PGK, NIO, AFA, BGN, XAU, SSP, AFN, HUF, XFU, AYM, KMF]

Как мне составить валютный запрос? Есть ли способ лучше?

TestCurrencyQuery.java:

package test;

import java.util.Locale;

import javax.money.CurrencyQuery;
import javax.money.CurrencyQueryBuilder;
import javax.money.CurrencyUnit;
import javax.money.Monetary;
import javax.money.MonetaryAmount;
import javax.money.format.MonetaryFormats;

import org.javamoney.moneta.FastMoney;

public class TestCurrencyQuery {
  public static void main(String[] args) {
    System.out.println(System.getProperty("java.vm.name"));
    System.out.println(System.getProperty("java.version"));
    System.out.println(System.getProperty("java.specification.vendor"));

    CurrencyQuery query = CurrencyQueryBuilder.of().setNumericCodes(840).build();
    CurrencyUnit cu = Monetary.getCurrency(query);
    MonetaryAmount amount = FastMoney.of(99.99, cu);
    System.out.println(MonetaryFormats.getAmountFormat(Locale.ENGLISH).format(amount));
  }
}

pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>test</groupId>
  <artifactId>test-jsr354</artifactId>
  <version>0.0.1-SNAPSHOT</version>

  <properties>
   <maven.compiler.source>1.8</maven.compiler.source>
   <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
        <groupId>org.javamoney</groupId>
        <artifactId>moneta</artifactId>
        <version>1.1</version>
    </dependency>
  </dependencies>
</project>

Консольный вывод:

Java HotSpot(TM) 64-Bit Server VM
1.8.0_31
Oracle Corporation
Exception in thread "main" javax.money.MonetaryException: Ambiguous request for CurrencyUnit: CurrencyQuery (
{Query.numericCodes=[840]}), found: [KHR, RON, XTS, FJD, LRD, MVR, BRL, ZMK, PKR, LBP, LYD, SDG, MXV, AED, XDR, STD, CDF, QAR, ISK, SHP, CSD, FRF, BMD, PTE, PLN, XUA, UYU, GYD, LAK, ZAR, ZMW, MKD, XSU, XAF, EEK, ILS, UGX, ITL, XPT, ROL, MUR, INR, TWD, KES, FIM, CHF, HNL, ARS, BGL, KRW, SBD, PHP, RUR, PYG, SRD, AWG, MXN, MGA, SGD, TRL, MZN, SOS, MOP, XBA, IRR, CZK, XFU, TRY, UZS, XFO, TTD, SDD, SCR, COP, ALL, XAU, SYP, USN, PAB, CUC, JMD, GNF, BHD, ANG, IDR, GWP, DEM, SLL, SVC, HRK, NLG, TMT, KZT, MTL, CUP, VEF, ZWN, NOK, LVL, CLF, TMM, BEF, VEB, MZM, DOP, GHS, BBD, XPF, CYP, UAH, BAM, TPE, BND, BYB, MGF, SIT, BWP, XBD, XCD, LSL, AYM, RUB, ADP, SEK, YUM, AOA, WST, GBP, ZWD, THB, ZWL, ESP, MAD, USS, ETB, NGN, AUD, TZS, XAG, VND, BTN, JOD, PGK, XBB, DKK, VUV, BYR, NZD, EGP, SSP, KMF, CNY, MWK, AZM, SAR, CVE, HUF, HTG, SRG, AZN, GIP, LUF, DJF, GEL, RWF, TJS, TOP, TND, ERN, OMR, GRD, MMK, LKR, FKP, NIO, ATS, KPW, PEN, AMD, IEP, BZD, XXX, BIF, GTQ, KYD, EUR, LTL, CRC, HKD, BGN, RSD, SZL, USD, KWD, CLP, MYR, BOB, AFA, GHC, JPY, AFN, GMD, MDL, IQD, BSD, MNT, NPR, MRO, XPD, DZD, NAD, CAD, BOV, KGS, ZWR, SKK, XOF, YER, BDT, XBC]
    at javax.money.spi.MonetaryCurrenciesSingletonSpi.getCurrency(MonetaryCurrenciesSingletonSpi.java:173)
    at javax.money.Monetary.getCurrency(Monetary.java:506)
    at test.TestCurrencyQuery.main(TestCurrencyQuery.java:21)

2 ответа

Решение

Как уже упоминалось, вы не можете получить доступ к CurrencyUnit через код валюты, используя эту реализацию. Если ваша задача строго принять код валюты в качестве параметра, вы можете создать свое собственное отображение. Лучше всего использовать базу данных, в которой вы можете хранить сопоставления между числовыми кодами и кодами валют.

package test;

import java.util.Locale;

import javax.money.CurrencyQuery;
import javax.money.CurrencyQueryBuilder;
import javax.money.CurrencyUnit;
import javax.money.Monetary;
import javax.money.MonetaryAmount;
import javax.money.format.MonetaryFormats;

import org.javamoney.moneta.FastMoney;

public class TestCurrencyQuery {
  public static void main(String[] args) {
    System.out.println(System.getProperty("java.vm.name"));
    System.out.println(System.getProperty("java.version"));
    System.out.println(System.getProperty("java.specification.vendor"));

    CurrencyQuery query = CurrencyQueryBuilder.of().setCurrencyCodes(getCurrencyCodesFromNumeric(840)).build();
    CurrencyUnit cu = Monetary.getCurrency(query);
    MonetaryAmount amount = FastMoney.of(99.99, cu);
    System.out.println(MonetaryFormats.getAmountFormat(Locale.ENGLISH).format(amount));
  }

    public String[] getCurrencyCodesFromNumeric(int... codes) {
        Collection<String> currencyCodes = // query db and return associated String currency codes;
        return currencyCodes.toArray(new String[currencyCodes.size()]);
    }
}

Согласно примечаниям для монет, валюты могут быть доступны только по коду валюты или языку. Доступ по числовому коду не обеспечивается этой реализацией. Вот как бы вы получили доступ по коду валюты USD:

CurrencyQuery query = CurrencyQueryBuilder.of().setCurrencyCodes("USD").build();
CurrencyUnit cu = Monetary.getCurrency(query);
MonetaryAmount amount = FastMoney.of(99.99, cu);
System.out.println(MonetaryFormats.getAmountFormat(Locale.ENGLISH).format(amount));

Если вы хотите добавить запрос на основе числового кода, я предлагаю вам обратиться к самому проекту.

Кроме того, вы можете получить все валюты с getCurrencies() и фильтр на основе числового кода:

CurrencyUnit cu = Monetary.getCurrencies().stream()
                .filter(c -> c.getNumericCode() == 840)
                .findAny()
                .orElseThrow(RuntimeException::new);

Наконец, вы можете реализовать свой собственный CurrencyProvider, который реализует getCurrency для поиска на основе числового кода.

Другие вопросы по тегам