January 30, 2011

Apex API String.format(); Exploring good & bad parts !

I recently came across useful and under documented Apex String API i.e.

String formattedString = String.format(String template, List<String> arguments)

String.format(..) is again based on Java MessageFormat class, its documentation says :

Treat the current string as a pattern that should be used for substitution in the same manner as apex:outputText.

Nice part of this String API is that it supports basic text substitution for ex.

// Create a Template String, that has tokens of form {index} 
String templateString = 'Hello {0}, Good to see you in {1}';
// String argument list or array matching each {index} in Template String.
String[] arguments = new String[] {'Ram' , 'India'};
// Call String.format() to get the token replaced
String formattedString = String.format(templateString, arguments);
// output : Hello Ram, Good to see you in India

Bad part about this String API is it only supports String arguments for token replacement. Though both Java’s MessageFormat and Visuaforce apex:outputText tag accept non-string arguments like Date, Datetime & Currency and are capable of doing very smart formatting with them. For ex. in visualforce one can format date using outputText as follows.

<apex:outputText value="The formatted time right now is: 
    {0,date,yyyy.MM.dd G 'at' HH:mm:ss z}">
   <apex:param value="{!NOW()}" />

output: The formatted time right now is: 2004.11.20 AD at 23:49:02 GMT  

Similar Java example with more options would be

Object[] arguments = {
     new Integer(7),
     new Date(System.currentTimeMillis()),
     "a disturbance in the Force"

 String result = MessageFormat.format(
     "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",

 output: At 12:30 PM on Jul 3, 2053, there was a disturbance
           in the Force on planet 7.

Sadly, if you try to do something similar with Apex it always fails for StringException.

Expected change in Apex String.format () API

Apex String.format (String pattern, String[] arguments) API, should take Object[] as argument instead of String[], this will help supporting more primitive data types i.e. datatime, date, currency and number etc, just like visualforce apex:outputText tag. This change would be safe and backward compatible, as all existing Apex code using String[] should work with Object[] too Smile

I am also, posting this as an Idea on SFDC Idea Exchange. Please vote this idea, if you agree with my views.