I went with annotation-based converter, although, in this particular case, type-based would probably be better.
First, I created
UUIDFormat annotation and UUIDFormatter (implements org.springframework.format.Formatter<UUID>) that does actual parsing/formatting. Next, UUIDFormatAnnotationFormatterFactory (implementing org.springframework.format.AnnotationFormatterFactory<UUIDFormat>) that maps annotation to formatter.Next step is to register this formatter with Spring. In Spring MVC an instance of a
org.springframework.format.support.FormattingConversionService is created automatically through the custom MVC namespace (when you use <mvc:annotation-driven/>). What we need to do is to create service bean and pass it to the MVC, like this: <mvc:annotation-driven conversion-service="conversionService"/>. In this case I decided not to go with custom service implementation and used default one: org.springframework.format.support.FormattingConversionServiceFactoryBean. Traditionally it is recommended to use installFormatters property of this bean to register your customer formatters , but it looks like it has been deprecated in 3.1. The new recommended way to do it is through formatterRegistrars property that takes a set of FormatterRegistrar implementations.So we create our own
UUIDFormatterRegistrar. Implementation is simple, override registerFormatters method:@Override
public void registerFormatters(FormatterRegistry registry) {
registry
.addFormatterForFieldAnnotation(new UUIDFormatAnnotationFormatterFactory());
}
There you can also register you converters, formatters for field type, etc.
Once that done, pass your registrar to the conversion service:
<mvc:annotation-driven conversion-service="conversionService" />
<bean id="conversionService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean"
p:formatterRegistrars-ref="formatterRegistrars" />
<util:set id="formatterRegistrars">
<bean class="net.koderllc.apparel.spring.UUIDFormatterRegistrar"/>
</util:set>
Spring is now aware about your custom formatters. Almost there.
SWF creates its own version of conversion service. We need to overwrite this and make SWF conversion service aware about Spring conversion service (the logic of this eludes me, but I might be missing something).
<webflow:flow-builder-services id="flowBuilderServices"
view-factory-creator="viewFactoryCreator" conversion-service="flowConversionService" />
<bean id="flowConversionService"
class="org.springframework.binding.convert.service.DefaultConversionService">
<constructor-arg ref="conversionService"/>
</bean>
And that's how we make SWF aware of your custom formatters.
I can't guarantee that this is the best way to do it, but that works for me. If anyone knows a way with less configuration involved - I'd be happy to hear it.