The Trouble with Strings
Data entering or leaving our application is frequently in string format (i.e. XML). As a developer, I would like a way to register custom data type converters for my business entities. Custom business data types might include social security number or US phone number.
Most data types that our applications use are String based when coming into/or leaving the application. For example, data we configure in XML documents, Web Service messages, User Interface collection and UI components are String types.
NEW Spring 3 Features
Validators
Spring 3 includes full JSR-303 Bean Validation support. This provides us with the ability to code or annotate our classes providing custom validation for our bean fields. In addition, Spring’s DataBinder can validate as well as bind our objects. To configure the validator, you can wire into your XML the following:
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
Or, Spring will load this automatically with (Roo configures this for you):
<mvc:annotation-driven/>
To add our own validator implementations see the Spring 3 Validation documentation. There we see how to implement the Java standard javax.validation.ConstraintValidator to write custom class and/or annotations for our specific needs.
Converters
Converters allow us to replace the old PropertyEditor support. Converters allow us to write classes that can convert to & from any types. This can prove very useful when you want to convert our Repository objects to/from our DTOs for example. This is a very power addition to Spring but is not the focus of this article. See Spring 3 Reference documentation for creating and registering converters.
Formatters
Formatters give us the common use-case of converting data to/from Strings. This article focuses on using Formatters.
Automatic Formatters
By default, Spring registers the common data types that we use on a daily basis, allowing us to convert data types to/from string. These common formatters (called “editors” prior to Spring 3) handle data types such as Numbers, Date, Property, Collection, File, Boolean, URL, etc.
How Does Formatting Work?
When we configure property injection in our XML files, we simply put in data in quotes. When Spring is injecting the value into the bean, Spring uses reflection to determine the recipient data type. Spring then looks up the data type in the registered converters & formatters and invokes the appropriate class to unmarshall it from String to the required data type.
If we have a service method setMaximumCount(Integer count) { .... }
We can configure that in XML as:
<bean id="myService" class="...MyService">
<property name="maximumCount" value="100" />
</bean>
In the above example, Spring goes through the following steps:
- String value configured in XML file for property
- Spring uses reflection inspecting the property type expected in the
MyService.setMaximumCount()method which is java.lang.Integer - Spring looks for a registered converter, formatter or
PropertyEditorforjava.lang.Integer - Spring invokes the class that unmarshalls the value from String, and invokes
setMaximumCount()
This is the same approach for Maps, Properties, Lists, Dates, URLs, etc. Very cool & very convenient!
What if we have a custom type like Social Security Number or US Phone Number? We may have a use-case to break the data into smaller chunks providing search by phone area code or SSN prefix.
Where Can We Find the Default Converters, Formatters, etc?
Take a look at org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser specifically the method getConversionService(). This method looks for the attributes conversion-service and validator in our <mvc:annotation-driven/> configuration.
Even cooler!!! This class looks for external conversion types for JSON, RSS, Java XML Binder and JSR-303!
For the full set of existing pre-registered PropertyEditors see: org.springframework.beans.PropertyEditorRegistrySupport in the method createDefaultEditors()
In Spring 3, also see org.springframework.format.support.FormattingConversionServiceFactoryBean where we will find reference to the JodaTime class conversion. This is very cool, if Spring finds it in the classpath, the formatter is registered.
Converting Old School in Spring 2.x
Steps to Setup Property Editors
Before 3.0, we registered custom types with org.springframework.beans.factory.config.CustomEditorConfigurer which is still supported in Spring 3.
- Create custom class implementing
java.beans.PropertyEditorSupportmethodsgetAsText/setAsText. - Register
org.springframework.beans.factory.config.CustomEditorConfigurerin our Spring application context XML file. The customEditors property element that accepts a map with key as our datatype and the value as our custom conversion (PropertyEditorSupport) class.
Although very useful, it lacks the Java 5 Generic support that we all know and love.
Converting New and Improved in Spring 3.x
Spring 3.0 introduced a typed implementation for custom type converters. The typed formatter interface is:
public interface Formatter<T> extends Printer<T>, Parser<T> {
}
Steps to Setup Property Formatters
- Create custom class implementing
org.springframework.format.Formattermethodsparse()/print(). - Create an application class that installs our custom types by extending
org.springframework.format.support.FormattingConversionServiceFactoryBeanand overriding theinstallFormatters()method - In the
installFormatters()method register your conversion type.
Implementing SSN Conversion
In the below example we will use Spring Roo classes with some minor tweaks for JodaTime API.
If you are unfamiliar with Joda time, you should be! JodaTime is THE replacement for the lame-duck that is Java’s date support.
The Employee Entity
Consider that we have an entity class called Employee:
package com.gordondickens.springformatter.entity;
import java.math.BigDecimal;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.validation.constraints.NotNull;
import org.hibernate.annotations.Type;
import org.joda.time.DateTime;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.roo.addon.entity.RooEntity;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.tostring.RooToString;
@Entity
@RooJavaBean
@RooToString
@RooEntity
public class Employee {
@NotNull
private String firstName;
@NotNull
private String lastName;
@NotNull
@Type(type = "org.joda.time.contrib.hibernate.PersistentDateTime")
@DateTimeFormat(pattern = "MM/dd/yyyy")
private DateTime hireDate;
@NotNull
private BigDecimal salary;
@Embedded
private SocialSecurityNumber socialSecurityNumber;
}
Notes for the example above:
- The class is marked as a JPA
@Entity - The hireDate field is a JodaTime class of DateTime (which you should absolutely be using).
- The hireDate field includes the Hibernate
@Typeannotation indicating the JodaTime class for Hibernate (see the Maven dependency below) - The hireDate field includes the Spring
@DateTimeFormatannotation for defining the acceptable field format. - The socialSecurityNumber field is of our SocialSecurityNumber type and is marked as JPA
@Embedded - Fields firstName, lastName and salary are annotated for JSR-303 validation with
@NotNull
JodaTime/Hibernate Maven Dependency
When configured with Roo, the application configures all of the dependencies for us. However, the addition of JodaTime for the hireDate field with Hibernate requires us to add the following dependency.
<groupId>joda-time</groupId>
<artifactId>joda-time-hibernate</artifactId>
<version>1.2</version>
Our Social Security Number Type
This is a simple (non-entity) class that will be embedded within our Employee class.
package com.gordondickens.springformatter.entity;
import javax.persistence.Embeddable;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.tostring.RooToString;
@RooJavaBean
@RooToString
@Embeddable
public class SocialSecurityNumber {
private String prefix;
private String middle;
private String suffix;
}
In the above example we have marked this class as a JPA @Embeddable type.
Our Social Security Number Formatter
First step is to write the converter to marshal SocialSecurityNumber to/from String format:
package com.gordondickens.springformatter.util;
import java.text.ParseException;
import java.util.Locale;
import org.apache.commons.lang.StringUtils;
import org.springframework.format.Formatter;
import com.gordondickens.springformatter.entity.SocialSecurityNumber;
public class SsnFormatter implements Formatter {
@Override
public String print(SocialSecurityNumber object, Locale locale) {
return object.toString();
}
@Override
public SocialSecurityNumber parse(String text, Locale locale)
throws ParseException {
SocialSecurityNumber securityNumber = new SocialSecurityNumber();
securityNumber.setPrefix(StringUtils.substringBefore(text, "-"));
securityNumber.setMiddle(StringUtils.substringBetween(text, "-"));
securityNumber.setSuffix(StringUtils.substringAfterLast(text, "-"));
return securityNumber;
}
}
We see the above SsnFormatter class implements the typed Formatter interface requiring us to implement the “parse” and “print” methods.
Our Custom Converter Installer
Next, we need to register our custom formatter:
package com.gordondickens.springformatter.util;
import org.springframework.format.FormatterRegistry;
import org.springframework.format.support.FormattingConversionServiceFactoryBean;
import com.gordondickens.springformatter.entity.SocialSecurityNumber;
import org.springframework.stereotype.Component;
@Component
public class FormattingConverters extends
FormattingConversionServiceFactoryBean {
@Override
public void installFormatters(FormatterRegistry registry) {
super.installFormatters(registry);
registry.addFormatterForFieldType(SocialSecurityNumber.class, new SsnFormatter());
}
}
Above, we see that the class SocialSecurityNumber is registered. NOTE: remember to call super.installFormatters(...) to get the core Spring converters. Also, notice that we are registering this class as a @Component so we need to use in our application context file.
Wiring our Converter In
The last step is to configure Spring to use our FormattingConverters class. This is done by attaching it to the directive.
<!-- Turns on support for mapping requests to Spring MVC @Controller methods Also registers default Formatters and Validators for use across all @Controllers --> <mvc:annotation-driven conversion-service="formattingConverters"/>
Summary
What we have seen is an improvement in the Spring type conversion which now supports Java 5 Generics. We connect this to the super very powerful <mvc:annotation-driven/> Spring directive. Let me know your thoughts.
Git the Code
Download the full code sample from:
git clone git://github.com/gordonad/Spring-3-Converters-Demo.git
Additional Reading
-
Spring 3.x Formatter & Converter Classes
FormattingConversionServiceFactoryBean– Installs Default FormattersConversionServiceFactory– Installs Default ConvertersFormattingConversionService– Installs Annotated Field Formatters
-
Spring 2.x Formatter & Converter Classes – a.k.a Property Editors
ResourceEditorRegistrar– Registers Resource Types (File, URL, etc) in PropertyEditorPropertyEditorRegistrarSupport– Creates Default PropertyEditors for Common Types (primitives, arrays, Collections, etc.)
-
Spring 3.x Validator Classes
SpringValidatingAdapter– Adapter for JSR-303 – Base for LocalValidatorFactoryBeanLocalValidatorFactoryBean– JSR-303 Setup, Implements SpringValidatingAdapter- Registering Custom Validators
-
Spring 2.x Validator Classes
- SpringSource Blog – Spring 3 Type Conversion and Validation

Pingback: Tweets that mention Technophile Blog » Using Spring 3.0 Custom Type Converter -- Topsy.com
This article is useful but its title is incorrect since you’re not demonstrating Spring 3 converters at all but Formatters which are a different animal. Additionally, Converters replace PropertyEditors — not Formatters. Formatters are strictly oriented around formatting output in various ways are designed to support things like localization.
Good article for learning spring formatters
Pingback: Enterprise Spring Best Practices – Part 2 – Application Architecture | Technophile Blog
I personally seem to go along with every little thing that ended up being authored within
“Using Spring 3.0 Custom Type Converter | Technophile Blog”.
Thank you for pretty much all the info.Thanks a lot-Kent