I'm really confused about how to customize a MonetaryAmountFormat
using the Moneta JSR-354 implementation.
My intention is to be able to parse both 1.23
and $3.45
as MonetaryAmount
s.
Here is my unit test:
@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);
}
Here is my 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();
}
}
I would have really liked to be able to parse the bidStr
with or without the $
using the single MonetaryAmountFormat
, but after spending a lot of time trying to find out how to make $
optional, I gave up. Unfortunately, I can't even figure out how to make 1.23
get parsed as USD. Moneta throws a NullPointerException
. Am I supposed to set a currency using the AmountFormatQueryBuilder
? What are all the keys that can be set using the AmountFormatQueryBuilder
? I searched for documentation, but couldn't find any anywhere, except for a couple of common keys, like pattern
.
JavaMoney does not seem to work well when trying to parse unqualified numbers (like 1.23
).
By default, the MonetaryAmountFormat
wants you to provide the currency name (like USD 1.23
):
MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(Locale.US);
MonetaryAmount amount = format.parse("USD 1.23");
If you set CurrencyStyle.SYMBOL
, then you can parse by currency name or symbol (so, either USD 1.23
or $3.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("$3.45");
That is probably the closest you are going to get with JavaMoney.
If you know you are only getting numbers from the same currency, you might be better off parsing the string elsewhere (with regexs or something) and converting to a consistent input format because (as you discovered), you easily get NullPointerException
s with no explanation when JavaMoney is unhappy.
As far as the available keys, you can peek at the constants on org.javamoney.moneta.format.AmountFormatParams
: pattern
, groupingSizes
, groupingSeparators
.
When setting the format, it is important to note that you must use the generic currency sign: ¤
. For instance, you might do .set("pattern", "¤#,##0.00")
.
Finally, rather than directly using the FastMoney
class from the Moneta RI, you can parse right from a MonetaryAmountFormat
:
// rather than using Monata directly:
MonetaryAmount amount = FastMoney.parse(bidStr, format);
// use the API:
MonetaryAmount amount = format.parse(bidStr);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With