使用Moneta(JavaMoney)JSR354实现定制MonetaryMountFormat

使用Moneta(JavaMoney)JSR354实现定制MonetaryMountFormat,java,jsr354,Java,Jsr354,对于如何使用Moneta JSR-354实现定制MonetaryMountFormat,我感到非常困惑 我的目的是能够将1.23和$3.45解析为MonetaryAmounts 下面是我的单元测试: @Test public void testString() { Bid bid = new Bid("1.23"); assertEquals(1.23, bid.getValue(), 0.0); System.out.println(bid); bid = n

对于如何使用Moneta JSR-354实现定制
MonetaryMountFormat
,我感到非常困惑

我的目的是能够将
1.23
$3.45
解析为
MonetaryAmount
s

下面是我的单元测试:

@Test
public void testString() {
    Bid bid = new Bid("1.23");
    assertEquals(1.23, bid.getValue(), 0.0);
    System.out.println(bid);

    bid = new Bid("$3.45");
    assertEquals(3.45, bid.getValue(), 0.0);
    System.out.println(bid);
}
这是我的班级:

public final class Bid {

    private static final CurrencyUnit USD = Monetary.getCurrency("USD");
    private MonetaryAmount bid;

    /**
     * Constructor.
     *
     * @param bidStr the bid
     */
    public Bid(String bidStr) {
        MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(
                AmountFormatQueryBuilder.of(Locale.US)
                .set("pattern", "###.##")
                .build());
        if (StringUtils.isNotBlank(bidStr)) {
            bidStr = bidStr.trim();
            bidStr = bidStr.startsWith("$") ? bidStr.substring(1) : bidStr;
            try {
                bid = FastMoney.parse(bidStr, format);
            } catch (NumberFormatException e) {
                bid = FastMoney.of(0, USD);
            }
        }
    }

    /**
     * Constructor.
     *
     * @param bidDouble the bid
     */
    public Bid(double bidDouble) {
        bid = FastMoney.of(bidDouble, USD);
    }

    public double getValue() {
        return bid.getNumber().doubleValue();
    }
}

我真的很想能够使用单一的
MonetaryAmountFormat
解析
bidStr
,但在花了很多时间试图找出如何使
$
可选之后,我放弃了。不幸的是,我甚至不知道如何将
1.23
解析为USD。Moneta抛出一个
NullPointerException
。我应该使用AmountFormatQueryBuilder设置货币吗?使用AmountFormatQueryBuilder可以设置的所有键是什么?我搜索了文档,但除了一些常用键之外,在任何地方都找不到任何文档,比如
pattern

JavaMoney在试图解析非限定数字(比如
1.23
)时似乎无法正常工作

默认情况下,
MonetaryAmountFormat
希望您提供货币名称(如
USD 1.23
):

如果设置了
CurrencyStyle.SYMBOL
,则可以按货币名称或符号进行分析(因此,
1.23美元或
3.45美元
):

这可能是你用JavaMoney得到的最接近的结果

如果您知道您只从同一种货币中获取数字,那么最好在其他地方解析字符串(使用regex或其他东西),并转换为一致的输入格式,因为(正如您所发现的那样),当JavaMoney不满意时,您很容易获得
NullPointerException
s而无需解释

就可用键而言,您可以查看
org.javamoney.moneta.format.AmountFormatParams
模式
分组大小
分组分离器

设置格式时,请务必注意,必须使用泛型:
·
。例如,您可以执行
.set(“pattern”、“·0.00”)

最后,您可以直接从
MonetaryAmountFormat
解析,而不是直接使用Moneta RI中的
FastMoney
类:

// rather than using Monata directly:
MonetaryAmount amount = FastMoney.parse(bidStr, format);

// use the API:
MonetaryAmount amount = format.parse(bidStr);

如果您使用的是自定义格式模式,那么您可以解析只包含一个没有货币的数字的字符串,但是您应该自己指定所需的货币。 以下是一个例子:

@Test
public void testParse_pattern_without_currency_sign_but_with_currency_in_context() {
    CurrencyUnit usd = Monetary.getCurrency("USD");
    AmountFormatContextBuilder builder = AmountFormatContextBuilder.of(US);
    builder.set(AmountFormatParams.PATTERN, "0.00"); // the pattern doesn't contains a currency sign ¤
    builder.set(CurrencyUnit.class, usd); // set expected currency
    AmountFormatContext context = builder.build();
    DefaultMonetaryAmountFormat format = new DefaultMonetaryAmountFormat(context);
    MonetaryAmount parsedAmount = format.parse("0.01 USD");
    assertSame(parsedAmount.getCurrency(), usd);
    assertEquals(parsedAmount.getNumber().doubleValueExact(), 0.01D);
    assertEquals(parsedAmount.toString(), "USD 0.01");
}
请注意,您需要使用
set(CurrencyUnit.class,usd)
创建上下文

但是,如果您尝试使用货币符号设置模式,例如
0.00·
,则会收到一个错误:
javax.money.format.monetaryparseeException:错误解析CurrencyUnit:无输入

我为此创建了一张罚单,请阅读并添加您的意见

// rather than using Monata directly:
MonetaryAmount amount = FastMoney.parse(bidStr, format);

// use the API:
MonetaryAmount amount = format.parse(bidStr);
@Test
public void testParse_pattern_without_currency_sign_but_with_currency_in_context() {
    CurrencyUnit usd = Monetary.getCurrency("USD");
    AmountFormatContextBuilder builder = AmountFormatContextBuilder.of(US);
    builder.set(AmountFormatParams.PATTERN, "0.00"); // the pattern doesn't contains a currency sign ¤
    builder.set(CurrencyUnit.class, usd); // set expected currency
    AmountFormatContext context = builder.build();
    DefaultMonetaryAmountFormat format = new DefaultMonetaryAmountFormat(context);
    MonetaryAmount parsedAmount = format.parse("0.01 USD");
    assertSame(parsedAmount.getCurrency(), usd);
    assertEquals(parsedAmount.getNumber().doubleValueExact(), 0.01D);
    assertEquals(parsedAmount.toString(), "USD 0.01");
}