javaformattingbigdecimalmessageformat

java.text.MessageFormat increase decimal places precision for BigDecimal / Number


I am using java.text.MessageFormatto replace place holders in a template that displays price per unit. Following is the piece of code that does it.

public String format(Object[] arguments, String pattern) {
    MessageFormat formatter = new MessageFormat("");
    formatter.applyPattern(pattern);
    return formatter.format(arguments);
}

pattern is

{0} {1} per {2}

and arguments are

argument[0] = "USD", argument[1] = BigDecimal(0.0002), argument[2] = "shirt"

I expected the formatter to output

"USD 0.0002 per shirt"

But formatter is reducing the precision and produces

"USD 0 per shirt"

It looks like MessageFormat is considering just 3 digits after the decimal point. "BigDecimal(0.01)" works as expected.

So is there any property I can tweak to tell the MessageFormat it should use a certain precision? Changing the pattern is not an option for me.

I can convert the argument to String from BigDecimal before formatting. But that will be my last option.

EDIT: The limit of 3 decimal points comes from NumberFormat.

private int    maximumFractionDigits = 3; 

is there a way we can change this value and make MessageFormat use this?


Solution

  • You can use formats such as {0,number,#.##} in the pattern. The Javadoc of MessageFormat has more details if you're interested.

    Since you cannot change the pattern, converting the objects to string before-hand would be the only solution though

    EDIT: actually I did not realize that the formats could be set programmatically:

    public static void main(String[] args) {
        Object[] argument = new Object[3];
        argument[0] = "USD";
        argument[1] = new BigDecimal(0.0002);
        argument[2] = "shirt";
    
        System.out.println(format(argument, "{0} {1} per {2}"));
    }
    
    public static String format(Object[] arguments, String pattern) {
        MessageFormat formatter = new MessageFormat(pattern);
    
        NumberFormat nf = NumberFormat.getNumberInstance();
        nf.setMaximumFractionDigits(7);
    
        for (int i = 0; i < arguments.length; i++) {
            if (arguments[i] instanceof BigDecimal) {
                formatter.setFormat(i, nf);
            }
        }
    
        return formatter.format(arguments);
    }
    

    This should print: USD 0.0002 per shirt