Performing type conversion

When request parameters are used to populate the model (commonly referred to as data binding), type conversion is required to parse String-based request parameter values before setting target model properties. Default type conversion is available for many common Java types such as numbers, primitives, enums, and Dates. Users also have the ability to register their own type conversion logic for user-defined types, and to override the default Converters.

Type Conversion Options

Starting with version 2.1 Spring Web Flow uses the type conversion and formatting system introduced in Spring 3 for nearly all type conversion needs. Previously Web Flow applications used a type conversion mechanism that was different from the one in Spring MVC, which relied on the java.beans.PropertyEditor abstraction. Spring 3 offers a modern type conversion alternative to PropertyEditors that was actually influenced by Web Flow's own type conversion system. Hence Web Flow users should find it natural to work with the new Spring 3 type conversion. Another obvious and very important benefit of this change is that a single type conversion mechanism can now be used across Spring MVC And Spring Web Flow.

Upgrading to Spring 3 Type Conversion And Formatting

What does this practically mean for existing applications? Existing applications are likely registering their own converters of type org.springframework.binding.convert.converters.Converter through a sub-class of DefaultConversionService available in Spring Binding. Those converters can continue to be registered as before. They will be adapted as Spring 3 GenericConverter types and registered with a Spring 3 org.springframework.core.convert.ConversionService instance. In other words existing converters will be invoked through Spring's type conversion service.

The only exception to this rule are named converters, which can be referenced from a binding element in a view-state:

public class ApplicationConversionService extends DefaultConversionService {	
    public ApplicationConversionService() {
        addDefaultConverters();
        addDefaultAliases();
        addConverter("customConverter", new CustomConverter());		
    }
}
				

<view-state id="enterBookingDetails" model="booking">
    <binder>
        <binding property="checkinDate" required="true" converter="customConverter" />
    </binder>
</view-state>
				

Named converters are not supported and cannot be used with the type conversion service available in Spring 3. Therefore such converters will not be adapted and will continue to work as before, i.e. will not involve the Spring 3 type conversion. However, this mechanism is deprecated and applications are encouraged to favor Spring 3 type conversion and formatting features.

Also note that the existing Spring Binding DefaultConversionService no longer registers any default converters. Instead Web Flow now relies on the default type converters and formatters in Spring 3.

In summary the Spring 3 type conversion and formatting is now used almost exclusively in Web Flow. Although existing applications will work without any changes, we encourage moving towards unifying the type conversion needs of Spring MVC and Spring Web Flow parts of applications.

Configuring Type Conversion and Formatting

In Spring MVC an instance of a FormattingConversionService is created automatically through the custom MVC namespace:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

	<mvc:annotation-driven/>

				

Internally that is done with the help of FormattingConversionServiceFactoryBean, which registers a default set of converters and formatters. You can customize the conversion service instance used in Spring MVC through the conversion-service attribute:

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

In Web Flow an instance of a Spring Binding DefaultConversionService is created automatically, which does not register any converters. Instead it delegates to a FormattingConversionService instance for all type conversion needs. By default this is not the same FormattingConversionService instance as the one used in Spring 3. However that won't make a practical difference until you start registering your own formatters.

The DefaultConversionService used in Web Flow can be customized through the flow-builder-services element:

<webflow:flow-builder-services id="flowBuilderServices" conversion-service="defaultConversionService" />
				

Connecting the dots in order to register your own formatters for use in both Spring MVC and in Spring Web Flow you can do the following. Create a class to register your custom formatters:

public class ApplicationConversionServiceFactoryBean extends FormattingConversionServiceFactoryBean {

    @Override
    protected void installFormatters(FormatterRegistry registry) {
        // ...
    }
	
}				

				

Configure it for use in Spring MVC:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <mvc:annotation-driven conversion-service="applicationConversionService" />
	
    <!-- 
    	Alternatively if you prefer annotations for DI:
    	  1. Add @Component to the factory bean.
    	  2. Add a component-scan element (from the context custom namespace) here.
    	  3. Remove XML bean declaration below.
      -->

    <bean id="applicationConversionService" class="somepackage.ApplicationConversionServiceFactoryBean">
	

				

Connection the Web Flow DefaultConversionService to the same "applicationConversionService" bean used in Spring MVC:

    <webflow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices" ... />
    	
    <webflow:flow-builder-services id="flowBuilderServices" conversion-service="defaultConversionService" ... />
    	
    <bean id="defaultConversionService" class="org.springframework.binding.convert.service.DefaultConversionService">
    	<constructor-arg ref="applicationConversionSevice"/>
    </bean>
				

Of course it is also possible to mix and match. Register new Spring 3 Formatter types through the "applicationConversionService". Register existing Spring Binding Converter types through the "defaultConversionService".

Working With Spring 3 Type Conversion And Formatting

An important concept to understand is the difference between type converters and formatters.

Type converters in Spring 3, provided in org.springframework.core, are for general-purpose type conversion between any two object types. In addition to the most simple Converter type, two other interfaces are ConverterFactory and GenericConverter.

Formatters in Spring 3, provided in org.springframework.context, have the more specialized purpose of representing Objects as Strings. The Formatter interface extends the Printer and Parser interfaces for converting an Object to a String and turning a String into an Object.

Web developers will find the Formatter interface most relevant because it fits the needs of web applications for type conversion.

Note

An important point to be made is that Object-to-Object conversion is a generalization of the more specific Object-to-String conversion. In fact in the end Formatters are reigstered as GenericConverter types with Spring's GenericConversionService making them equal to any other converter.

Formatting Annotations

One of the best features of the new type conversion is the ability to use annotations for a better control over formatting in a concise manner. Annotations can be placed on model attributes and on arguments of @Controller methods that are mapped to requests. Out of the box Spring provides two annotations NumberFormat and DateTimeFormat but you can create your own and have them registered along with the associated formatting logic. You can see examples of the DateTimeFormat annotation in the Spring Travel and in the Petcare along with other samples in the Spring Samples repository.

Working With Dates

The DateTimeFormat annotation implies use of Joda Time. If that is present on the classpath the use of this annotation is enabled automatically. By default neither Spring MVC nor Web Flow register any other date formatters or converters. Therefore it is important for applications to register a custom formatter to specify the default way for printing and parsing dates. The DateTimeFormat annotation on the other hand provides more fine-grained control where it is necessary to deviate from the default.

For more information on working with Spring 3 type conversion and formatting please refer to the relevant sections of the Spring documentation.