3

Take this SSCCE (with Joda-Money library installed):

public static void main(String[] args) {
    BigDecimal bd = new BigDecimal("100");
    MoneyFormatter mf = new MoneyFormatterBuilder().appendLiteral("$ ").appendAmount(MoneyAmountStyle.LOCALIZED_GROUPING).toFormatter();
    String money_as_string = mf.print(Money.of(CurrencyUnit.USD, bd)); // The MoneyFormatter is what printed this string...
    System.out.println(money_as_string);
    Money money = mf.parseMoney(money_as_string); // You think it should be able to parse the string it gave me, right?
}

I used the MoneyFormatter to print the String: money_as_string. My (reasonable?) expectation was that I could use the same MoneyFormatter to parse the string back into a Money object. But, alas, no dice. It throws this error:

Exception in thread "main" org.joda.money.format.MoneyFormatException: Parsing did not find both currency and amount: $ 100.00
    at org.joda.money.format.MoneyFormatter.parseBigMoney(MoneyFormatter.java:237)
    at org.joda.money.format.MoneyFormatter.parseMoney(MoneyFormatter.java:258)
    at test4.Test12.main(Test12.java:35)

So, my question is: how exactly does one get a Money object from a String?

EDIT: @durron597, your information was helpful but did not answer the question. How, exactly, do you go from a String to a Money object then?

I added code to remove the dollar sign:

public static void main(String[] args) {
    BigDecimal bd = new BigDecimal("100");
    MoneyFormatter mf = new MoneyFormatterBuilder().appendLiteral("$ ").appendAmount(MoneyAmountStyle.LOCALIZED_GROUPING).toFormatter();
    String money_as_string = mf.print(Money.of(CurrencyUnit.USD, bd)); // The MoneyFormatter is what printed this string...
    System.out.println(money_as_string);
    Money money = mf.parseMoney(money_as_string.replace("$", "").trim()); // You think it should be able to parse the string it gave me, right?
}

and I got this:

Exception in thread "main" org.joda.money.format.MoneyFormatException: Text could not be parsed at index 0: 100.00
    at org.joda.money.format.MoneyFormatter.parseBigMoney(MoneyFormatter.java:233)
    at org.joda.money.format.MoneyFormatter.parseMoney(MoneyFormatter.java:258)
    at test4.Test12.main(Test12.java:35)

So, it can't parse the text with or without the currency symbol.

Can anyone get the parseMoney() function to work, ever??

1 Answer 1

3

So the first thing that stood out to me is that you were using appendLiteral and not appendCurrencySymbolLocalized (what if you were using CurrencyUnit.EUR? You wouldn't want a $).

However, when you change it to this:

MoneyFormatter mf = new MoneyFormatterBuilder()
        .appendCurrencySymbolLocalized()
        .appendAmount(MoneyAmountStyle.LOCALIZED_GROUPING)
        .toFormatter();

Your code instead throws this exception:

Exception in thread "main" java.lang.UnsupportedOperationException: MoneyFomatter has not been configured to be able to parse
    at org.joda.money.format.MoneyFormatter.parse(MoneyFormatter.java:281)
    at org.joda.money.format.MoneyFormatter.parseBigMoney(MoneyFormatter.java:229)
    at org.joda.money.format.MoneyFormatter.parseMoney(MoneyFormatter.java:258)
    at MoneyTest.main(MoneyTest.java:17)

Further examination reveals this telling line in the javadoc:

appendCurrencySymbolLocalized

publicMoneyFormatterBuilderappendCurrencySymbolLocalized()

Appends the localized currency symbol to the builder. The localized currency symbol is the symbol as chosen by the locale of the formatter.

Symbols cannot be parsed.

Returns: this, for chaining, never null

Why might that be? Probably because currency symbols are ambiguous. Many countries use a dollar. Here are some examples:

In addition to those countries of the world that use dollars or pesos, a number of other countries use the $ symbol to denote their currencies, including:

  • Nicaraguan córdoba (usually written as C$)
  • Samoan tālā (a transliteration of the word dollar)
  • Tongan paʻanga
  • Zimbabwe (usually written as Z$)

Try this code:

MoneyFormatter mf = new MoneyFormatterBuilder()
        .appendCurrencyCode()
        .appendAmount(MoneyAmountStyle.LOCALIZED_GROUPING)
        .toFormatter();

This will make something like USD 100.00 print, which will be parsed properly. If you absolutely must have the dollar symbol, you are going to need to implement your own printer/parser. Or you could use this one:

import java.io.IOException;
import java.math.BigDecimal;

import org.joda.money.BigMoney;
import org.joda.money.CurrencyUnit;
import org.joda.money.IllegalCurrencyException;
import org.joda.money.Money;
import org.joda.money.format.MoneyAmountStyle;
import org.joda.money.format.MoneyFormatter;
import org.joda.money.format.MoneyFormatterBuilder;
import org.joda.money.format.MoneyParseContext;
import org.joda.money.format.MoneyParser;
import org.joda.money.format.MoneyPrintContext;
import org.joda.money.format.MoneyPrinter;

public class MoneyTest {
    private static enum DollarParserPrinter implements MoneyParser,
            MoneyPrinter {
        INSTANCE;

        private static final String DOLLAR_SYMBOL = "$ ";

        @Override
        public void parse(MoneyParseContext context) {
            int endPos = context.getIndex() + 2;
            if (endPos > context.getTextLength()) {
                context.setError();
            } else {
                String code =
                        context.getTextSubstring(context.getIndex(), endPos);
                if(DOLLAR_SYMBOL.equals(code)) {
                    context.setCurrency(CurrencyUnit.USD);
                    context.setIndex(endPos);
                }
            }
        }

        @Override
        public void print(MoneyPrintContext context, Appendable appendable,
                BigMoney money) throws IOException {
            if(CurrencyUnit.USD == money.getCurrencyUnit()) {
                appendable.append(DOLLAR_SYMBOL);
            } else {
                throw new IllegalCurrencyException("This parser only knows how to print US Dollar money!");
            }
        }
    }

    public static void main(String[] args) {
        BigDecimal bd = new BigDecimal("100");
        MoneyFormatter mf =
                new MoneyFormatterBuilder().append(DollarParserPrinter.INSTANCE, DollarParserPrinter.INSTANCE)
                        .appendAmount(MoneyAmountStyle.LOCALIZED_GROUPING)
                        .toFormatter();
        String money_as_string = mf.print(Money.of(CurrencyUnit.USD, bd)); 
        System.out.println(money_as_string);
        Money money = mf.parseMoney(money_as_string);
        System.out.println(money);
    }
}
1
  • Edited my answer in response to you.
    – ryvantage
    Commented May 12, 2014 at 21:14

Not the answer you're looking for? Browse other questions tagged or ask your own question.