Spring & JSF integration: Converters
String
to some other type. Both Spring and JSF have converter strategies to deal with this, although they are really quite different in both their design and capabilities. Lets start by looking at Spring.Spring 3 introduced a whole new conversion framework that allows objects of any type to be converted to any other type (as long as an appropriate converter is registered). Keith Donald has written about how the new conversion process works. Spring MVC was also updated at version 3 to make use of the converter service when dealing with request parameters, for example, passing a String
parameter to the following controller method:
@RequestMapping public void example(@RequestParam Integer value)
will result in the StringToNumber
converter (via the StringToNumberConverterFactory
) running to create the equivalent Integer
.
Unlike Spring, converters in JSF only deal with converting objects to and from Strings. The javax.faces.convert.Converter
interface defines two methods: getAsString
(used when rendering) converts an object to a string and getAsObject
(used when decoding postbacks) converts a previously rendered string back to an object.
By default, you can register converters with JSF either by adding an entries to your faces-config.xml
or by using the @FacesConverter
annotation. I have been working to allow you to also register JSF converters by simply declaring them as Spring beans. Using Spring beans gives you a number of advantages over vanilla JSF. For example, you easily can inject other collaborator beans and you can use Spring AOP. To use the converter bean simply refer to its ID from JSF:
@Component public class MyConverter implements Converter { @Autowire private MyHelper helper; ... }
<h:inputText value=”#{bean.value}”> <f:converter converterId=”myConverter”/> </h:inputText>
In order to save referencing the same converter ID over and over again, JSF allows you to register a converter “for” a particular class. To support this with Spring a new @ForClass
annotation has been introduced:
@Component @ForClass(MyCustomType.class) public class MyConverter implements Converter { ... }
The example above will use MyConverter
every time an object of MyCustomType
needs converting.
For convenience I have also provided a variant of javax.faces.convert.Converter
that supports generics. The org.springframework.springfaces.convert.Converter
interface has an identical signature to the standard JSF version. When using this interface with @ForClass
you can also omit the value on the annotation:
@Component @ForClass public class MyConverter implements Converter<MyCustomType> { ... }
You can also implement more complex “for class” bindings using the ConditionalForClass
interface (see the JavaDoc for details).
Finally, there is also support for using JSF converters (no matter how they are registered) from Spring MVC. The GenericFacesConverter
is a Spring ConditionalGenericConverter
that, when registered, automatically delegates to JSF.
For example, assuming that MyConverter
is registered for MyCustomType
the following MVC mapping will work:
@RequestMapping("/example") public void example(@RequestParam MyCustomType value) { .... }
You can also use the @FacesConverterId
annotation if you need to reference a specific JSF converter:
@RequestMapping("/example") public void example(@RequestParam @FacesConverterId("myOtherConverter") MyOtherCustomType value) { .... }
If you want to see this in action take a look at ConverterExampleController from the showcase application.
Reference: Integrating Spring & JavaServer Faces : Converters from our JCG partner Phillip Webb at the Phil Webb’s Blog blog.