Use the Spring 3 Formatter SPI for Custom Formatting

In a previous Developer.com article, I wrote about the new formatting annotations provided in Spring 3. The formatting annotations, as I described in that article, enable you to format numbers, dates and times quickly and easily. Those annotations actually are part of Spring 3's Formatter SPI, which allows you to define custom parse and print capabilities for just about any type.

In this follow-up article, I explain how the new Formatter SPI in Spring 3 gives you the power to build custom formatting capabilities, demonstrating how you can create parsing/printing annotations such as @NumberFormat and @DateTimeFormat .

Spring 3 Custom Formatting: When, Why and Where to Use

You use field formatting to render bean property data. In particular, you can use the rendering capability in user interfaces and report displays -- like those found in Web applications. Figure 1 shows an example of a field formatter.



Figure 1. Formatters Can Format Bean Data for Display

You also use field formatting to help parse and convert string data (e.g. as provided in a Web form) into a variety of bean field types. In this way, the field formatting offers an alternative to the type conversion system (added to Spring 3) and PropertyEditors found in the Spring Framework. Figure 2 shows a Web form being parsed and converted to the Phone object of a Customer using a formatter.



Figure 2. Formatters Parse and Convert String Data

There is a bit overlap between Spring 3's type conversion system and the Formatter SPI. So when should you use the type conversion system (also known as the Converter SPI) and when should you use the formatting system? The Spring documentation provides a recommendation:

"In general, use the Converter SPI when you need to implement general-purpose type conversion logic; for example, for converting between a java.util.Date and a java.lang.Long. Use the Formatter SPI when you're working in a client environment, such as a Web application, and need to parse and print localized field values."

Spring 3 Custom Formatting: What You Need

In Spring 3, the Formatter SPI interfaces and classes are located in org.springframework.context-3.0.X.RELEASE.jar. You may need additional JAR files depending on your application and how you use the Formatter SPI.

The rest of this article demonstrates the Formatter SPI. The code shown is available in a small demonstration application provided with this article. The following are the JAR files used in the application, beyond the context JAR:

org.springframework.beans-3.0.4.RELEASE.jar

org.springframework.core-3.0.4.RELEASE.jar

org.springframework.web-3.0.4.RELEASE.jar

org.springframework.web.servlet-3.0.4.RELEASE.jar

com.springsource.org.apache.commons.logging-1.1.1.jar

org.springframework.asm-3.0.4.RELEASE.jar

org.springframework.expression-3.0.4.RELEASE.jar

The Formatter Interface

If you need additional formatting beyond the formatting annotations, or if do not like the formatting that the annotations provide, you can add your own custom formatting. At the heart of the formatting system is the formatter interface. The formatter interface is typed to allow you to display or parse strings from your designated target type.

This interface requires all implementers to provide parse( ) and print( ) methods. As the names of these methods suggest, the parse method takes a string and produces an instance of the target type. The print method, on the other hand, takes an instance of the target type and produces a string representation of the target type object. Both methods take a locale parameter so that the string (whether input or output) is localized to the user's preference.

To learn how to use the formatter interface, suppose you defined your own CustomerSSN (Social Security Number) type, which you use to define a SSN property in a Customer class as shown in Listing 1.

Listing 1. Pertinent Parts of the Customer and CustomerSSN Classes

public class Customer {

...

private CustomerSSN ssn = new CustomerSSN();

...

}



public class CustomerSSN {



private int area; //first 3

private int group; //middle 2

private int serial; // last 4

...

}

Customer objects have a social security number property as defined by the CustomerSSN type.

Listing 2 shows an example custom formatter for CustomerSSN. CustomerSSN serves as the example formatter's target type.

Listing 2. SSNFormatter is a Formatter Implementation

public class SSNFormatter implements Formatter<CustomerSSN> {



public String print(CustomerSSN ssn, Locale locale) {

return ssn.getArea() + "-" +

ssn.getGroup() + "-" + ssn.getSerial();

}



public CustomerSSN parse(String source, Locale locale)

throws ParseException {

int area = Integer.parseInt(source.substring(0, 3));

int group = Integer.parseInt(source.substring(4, 6));

int serial = Integer.parseInt(source.substring(7, 11));

return new CustomerSSN(area, group, serial);

}

}

SSNFormatter parses and converts strings to CustomerSSN objects and prints or displays CustomerSSN objects to a "999-99-9999" string.

Now, in order to use a formatter implementation, register the formatter with a FormatterRegistry (org.springframework.forma). Extend the FormattingConversionServiceFactoryBean (org.springframework.format.support) to register your formatters with a FormatterRegistry. In Listing 3 below, a new class extending FormattingConversionServiceFactoryBean registers the SSNFormatter with the FormatterRegistry.

Listing 3. MyFormattingFactory Adds the Custom Formatter to the Formatter Registry

public class MyFormattingFactory extends

FormattingConversionServiceFactoryBean {



public void installFormatters(FormatterRegistry registry) {

super.installFormatters(registry);

registry.addFormatterForFieldType(CustomerSSN.class,

new SSNFormatter());

}

}

The SSNFormatter is registered with the formatter in order to parse and display any encountered CustomerSSN objects.

By default, the <mvc:annotation-driven /> Spring XML configuration element automatically registers Spring formatters and converters for common types. This is what allows the @NumberFormat and @DateTimeFormat formatting annotations to work. You need to alert Spring to use your FormattingConversionServiceFactoryBean to register your custom formatters. To do this, add a conversion-service attribute to the <mvc:annotation-driven /> element as follows.

<mvc:annotation-driven conversion-service="myFormattingFactory" />

<bean id="myFormattingFactory"

class="com.intertech.formatting.MyFormattingFactory" />

With the formatter in place, CustomerSSN objects can be displayed/parsed appropriately in an HTML form. In Figure 3 below, you see CustomerSSN data displayed in a form without (above) and with (below) the custom formatter in place.



Figure 3. CustomerSSN Data Displayed with and Without the Custom Formatter

The SSNFormatter allows CustomerSSN data to be displayed appropriately in a form. While not shown, the same formatter allows string data from the form to be parsed as a CustomerSSN object.

Page 1 of 2