使用 Moneta (JavaMoney) JSR 354 实现自定义 MonetaryAmount 格式
Customizing a MonetaryAmountFormat using the Moneta (JavaMoney) JSR354 implemenation
我真的很困惑如何使用 Moneta JSR-354 实现来自定义 MonetaryAmountFormat
。
我的意图是能够将 1.23
和 .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(".45");
assertEquals(3.45, bid.getValue(), 0.0);
System.out.println(bid);
}
这是我的 class:
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
解析为美元。 Moneta 抛出 NullPointerException
。我应该使用 AmountFormatQueryBuilder
设置货币吗? AmountFormatQueryBuilder
可以设置哪些键?我搜索了文档,但找不到任何地方,除了几个常用键,比如 pattern
.
JavaMoney 在尝试解析不合格的数字(如 1.23
)时似乎效果不佳。
默认情况下,MonetaryAmountFormat
希望您提供货币名称(如 USD 1.23
):
MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(Locale.US);
MonetaryAmount amount = format.parse("USD 1.23");
如果设置CurrencyStyle.SYMBOL
,则可以按货币名称或符号解析(因此,USD 1.23
或.45
):
AmountFormatQuery formatQuery = AmountFormatQueryBuilder.of(Locale.US)
.set(CurrencyStyle.SYMBOL)
.build();
MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(formatQuery);
MonetaryAmount amount1 = format.parse("USD 1.23");
MonetaryAmount amount2 = format.parse(".45");
这可能是您使用 JavaMoney 最接近的结果。
如果你知道你只从同一种货币中获取数字,你可能最好在别处解析字符串(使用正则表达式或其他东西)并转换为一致的输入格式,因为(正如你发现的那样),你很容易得到NullPointerException
当 JavaMoney 不高兴时没有任何解释。
就可用键而言,您可以查看 org.javamoney.moneta.format.AmountFormatParams
上的常量:pattern
、groupingSizes
、groupingSeparators
.
设置格式的时候需要注意的是一定要使用通用的currency sign:¤
。例如,你可以做 .set("pattern", "¤#,##0.00")
.
最后,您可以直接从 MonetaryAmountFormat
:
中解析,而不是直接使用 Moneta RI 中的 FastMoney
class
// 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.MonetaryParseException: Error parsing CurrencyUnit: no input
.
我为此创建了一个工单Lenient Formatter: Parse a string with a number but without a currency code,请阅读并添加您的意见。
我真的很困惑如何使用 Moneta JSR-354 实现来自定义 MonetaryAmountFormat
。
我的意图是能够将 1.23
和 .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(".45");
assertEquals(3.45, bid.getValue(), 0.0);
System.out.println(bid);
}
这是我的 class:
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
解析为美元。 Moneta 抛出 NullPointerException
。我应该使用 AmountFormatQueryBuilder
设置货币吗? AmountFormatQueryBuilder
可以设置哪些键?我搜索了文档,但找不到任何地方,除了几个常用键,比如 pattern
.
JavaMoney 在尝试解析不合格的数字(如 1.23
)时似乎效果不佳。
默认情况下,MonetaryAmountFormat
希望您提供货币名称(如 USD 1.23
):
MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(Locale.US);
MonetaryAmount amount = format.parse("USD 1.23");
如果设置CurrencyStyle.SYMBOL
,则可以按货币名称或符号解析(因此,USD 1.23
或.45
):
AmountFormatQuery formatQuery = AmountFormatQueryBuilder.of(Locale.US)
.set(CurrencyStyle.SYMBOL)
.build();
MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(formatQuery);
MonetaryAmount amount1 = format.parse("USD 1.23");
MonetaryAmount amount2 = format.parse(".45");
这可能是您使用 JavaMoney 最接近的结果。
如果你知道你只从同一种货币中获取数字,你可能最好在别处解析字符串(使用正则表达式或其他东西)并转换为一致的输入格式,因为(正如你发现的那样),你很容易得到NullPointerException
当 JavaMoney 不高兴时没有任何解释。
就可用键而言,您可以查看 org.javamoney.moneta.format.AmountFormatParams
上的常量:pattern
、groupingSizes
、groupingSeparators
.
设置格式的时候需要注意的是一定要使用通用的currency sign:¤
。例如,你可以做 .set("pattern", "¤#,##0.00")
.
最后,您可以直接从 MonetaryAmountFormat
:
FastMoney
class
// 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.MonetaryParseException: Error parsing CurrencyUnit: no input
.
我为此创建了一个工单Lenient Formatter: Parse a string with a number but without a currency code,请阅读并添加您的意见。