简体   繁体   中英

Find CurrencyUnit from ISO **numeric** currency code

I'm trying to format an amount using the correct formatting rules, given the ISO 4217 numeric currency code.

For example, given an amount of 99.99 and numeric code 840, I expect to produce a string 'USD 99.99' or similar.

Looking at the JSR 354 implementation, it seems that i need to first find the appropriate currency unit. However, I cant seem to compose a valid CurrencyQuery for this purpose.

Given

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));

I receive the following exception:

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]

How should I compose the currency query? Is there a better way?

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>

Console output :

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)

Per the notes for moneta , currencies can only be accessed by Currency Code or Locale. Access by Numeric Code is not provided by this implementation. Here is how you would access by currency code 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));

If you would like to contribute a query based on Numeric Code, I suggest you reach out to the project itself.

Alternatively, you could retrieve all currencies with getCurrencies() and filter based on the numeric code:

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

Finally, you could implement your own CurrencyProvider that implements getCurrency to search based on Numeric Code.

As already mentioned, you're not able to access CurrencyUnit via Currency Code using this implementation. If your task is strictly accept currency code as parameter, you can create your own mapping. The better approach is to using database where you can store mapping between numeric codes and currency codes.

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()]);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM