Saturday 25 June 2011

What is MessageFormat?

There are many ways to create a user readable message in Java, differing in the complication level, performance and capabilities. The easiest is to create the String message by using “+” operator and casting all message parameters to string. If the message is longer or more complicated you can use StringBuilder instead. For more advanced formating a String.format() method may be more useful.
Today I want to show you a Java class designed specially for advanced message formatting – MessageFormat. Its advantage over the already mentioned methods is that allows even more advanced value formatting, dependency on Locale and precompilation of the message.
The basic usage is very easy: create and compile a message pattern with placeholders in place of values. At runtime supply values and create a formatted final String. See the example:

Object[] arguments = new Object[] {"John"};
MessageFormat message = new MessageFormat("User {0} logged in.");

System.out.println(message.format(arguments));

As a result of running this code you will get the following output: “User John logged in.”
Obviously you can do much more complicated things than that. The following example is a message that informs on the number of people living in specified city. The trick is that the message is in italian, so we specify the locale to get the italian-specific way of formating numbers (with a dot separating thousands instead of a coma):
Object[] arguments = new Object[] {
12345, // argument 0 - number of people
"Roma" // argument 1 - name of the city
};

MessageFormat message = new MessageFormat(
"{0} persone vivono a {1}", Locale.ITALIAN);

System.out.println(message.format(arguments));

The output of this code is: “12.345 persone vivono a Roma” – as expected number formatting is italian-specific.
Finally something really complicated – formatting of time, currency, number and also plural version of a noun:

Object[] arguments = new Object[] {
"John", // argument 0 - user name
12.45, // argument 1 - money paid
3, // argument 2 - amount of beers
new Date() // argument 3 - date of transaction
};

MessageFormat message = new MessageFormat(
"User {0} paid {1, number, currency} " +
"for {2} at {3, time, full}", Locale.FRANCE);

// fancy way to format the 2nd value - amount of beer bought
ChoiceFormat beerFormat = new ChoiceFormat(
new double[] {0, 1, 2},
new String[] {"no beer", "one beer", "{2, number,0.0} beers"} );
// set beerFormat to be used for argument number 2
message.setFormat(2, beerFormat);

System.out.println(message.format(arguments));

The code above will print “User John paid 12,45 € for 3,0 beers at 22 h 34 GMT”. By supplying different arguments and changing locale to US you might also get something like this: “User John paid $12.45 for one beer at 10:35:38 AM GMT”.
It is important to say that there is another way to use the ChoiceFormat above to format beer amount. For the purpose of readability we have created it as a separate object, but it could also be inlined in message format string:
MessageFormat message3 = new MessageFormat(
"User {0} paid {1, number, currency} " +
"for {2, choice,0#no beer|1#one beer|2#{2,number,0.0} beers} " +
"at {3, time, full}", Locale.FRANCE);
This is important as you may want to load message formats from a resource file, so all operations should be possible to be done in format text.

No comments:

Post a Comment