Spring Converters and Formatters
Spring 3.0 introduces a simple Converter interface that you can implement and reuse anywhere in Spring. You can use them in Spring MVC to convert request String values to Controller method parameter values of any Object type that you can write a Converter for.
Updated inversion of control (IoC) tutorials and dependency injection examples
TheServerSide has been updating its resources in terms of the Spring framework, Java EE contexts and various different approaches to inversion of control (IoC) and dependency injection (DI). Check out these newer resources on the topic:
- Inversion of control explained fast with a Spring IoC example
- Spring MVC Java web development with Spring Boot
- Drawbacks to IoC and how to solve inversion of control problems
- Spring IoC vs. Google Guice's inversion of control approach
- Getting started with Google Guice
- Getting started with the Spring IoC container
- The beauty of Spring without XML: Annotation based IoC
1) Converter interface
Before Spring 3.0, to convert String values in your Spring configuration
file to an Object type in your classes that weren't built into either
the JDK or Spring, you had to implement your own PropertyEditors. The
great thing about PropertyEditors are that they are defined by the
JavaBean specification and can be reused anywhere that uses
PropertyEditors. The problem with PropertyEditors were that they are
stateful and therefore not thread-safe. They also can only convert to and from
String to Object types. And if you also wanted to use
them in Spring MVC, you had to bind them in all your Controllers.
Spring 3.0 now introduces a simple Converter interface that you can implement and reuse
anywhere in Spring. And you can use them in Spring MVC to convert request String values to
Controller method parameter values of any Object type that you can write a Converter for.
The Converter interface is rather simple:
public interface Converter<S,T> {
public T convert(S source);
}
By implementing this interface the S source object can be converted to the T return type.
This means you are not bound to convert to and from Strings only.
public class EncryptedKeyToBankAccountConverter implements Converter<String, BankAccount> {
public BankAccount convert(String key) {
if (key == null) {
throw IllegalArgumentException();
}
String decryptedKey = Decryptor.decrypt(key);
if (decryptedKey == null) {
throw InvalidKeyException(); // Custom Exception from your application
}
return new BankAccount(decryptedKey);
}
}
It is important that you keep your Converter stateless, and guarantee that the convert method never returns null.
If an invalid parameter value is passed, throw an IllegalArgumentException. And instead of ever returning null throw
another Exception.
2) Using converters and registering your custom converters
The only Spring configuration requirement is to create a bean of type ConversionService.
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"/>
and register your converters via the "converters" property of ConversionServiceFactoryBean.
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="com.serverside.EncryptedKeyToBankAccountConverter" />
</list>
</property>
</bean>
Now Spring will use your converters to convert String configuration values to the correct Object type.
public class BankCustomer {
BankAccount checkingAccount;
public void setCheckingAccount(BankAccount checkingAccount) {
this.checkingAccount = checkingAccount;
}
}
<bean id="bankCustomer" class="com.serverside.convertertips.BankCustomer" scope="session">
<property name="checkingAccount" value="67dsdh8673hnkluye3nd38dn4j78vbn3"/>
</bean>
Here the BankCustomer bean will get a BankAccount injected into it via converting the value string into a BankAcount object.
Normally a BankCustomer and BankAccount object wouldn't be used as beans, since they seem to be domain objects.
And if you want to use them in your Spring MVC application, just refer to your conversionService bean via the new
mvc namespace.
<mvc:annotation-driven conversion-service="conversionService"/>
If your web page encrypts the BankAccount number/key in the client side and sends it to the server side to your
Controller method. Spring will call your converter which will decrypt the String, create a BankAccount object and
pass it in as the value of the bankAccount parameter value.
@Controller
public class BankAccountController {
@Autowired
BankAccountService bankAccountService;
@RequestMapping(value="/depositList", method=RequestMethod.GET)
public String getListOfDeposits(@RequestParam("accountKey")BankAccount bankAccount, ModelMap model) {
List<Deposit> deposits = bankAccountService.getListOfDeposits(bankAccount);
model.addObject(deposits);
return "depositList";
}
}
Spring has also introduced a Formatter API which can convert types of objects via formats. This means that a date formatted
MM/DD/YYYY can be converted to one type of Joda DateTime object, but if it is formatted DD/MM/YYYY it can be converted to a different Joda DateTime object.
In most cases, the issue comes when you have different formats for the same type of data. This could be because of internationalization.
Spring's new Expression Language can also leverage Converters.
Converters combined with Spring's new Formatter API and Spring Expression Language goes well beyond the capabilities of PropertyEditors, and greatly reduces the amount of code necessary prior to Spring 3.0.
This is a welcome addition and after using it a few times I think you will find it extremely powerful
and easy to create and use.