I searched for the below problem, but couldn\'t find an answer.
I want to use spring\'s conversion service by writing my custom converter that implements org.spri
It's enough to override the ConversionServiceFactoryBean.afterPropertiesSet() and set the ConversionService object to your converters there. Let your converters implement some interface that allows to set a ConversionService object, say ConversionServiceAware. The only problem is to get access to the registered converters, so you'll also have to override the 'setConverters()' method.
public class MyFormattingConversionServiceFactoryBean extends FormattingConversionServiceFactoryBean {
private Set<?> cachedConverters = new LinkedHashSet<>();
@Override
public void setConverters(Set<?> converters) {
super.setConverters(converters);
this.cachedConverters = new LinkedHashSet<>(converters);
}
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
FormattingConversionService conversionService = getObject();
for (Object converter : cachedConverters) {
if (converter instanceof ConversionServiceAware) {
((ConversionServiceAware) converter).setConversionService(conversionService);
}
}
}
}
This variant works for me.
If you use java configuration, you can add your converters to existing GenericConversionService
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/annotation/Autowired.html
Config methods may have an arbitrary name and any number of arguments; each of those arguments will be autowired with a matching bean in the Spring container. Bean property setter methods are effectively just a special case of such a general config method. Such config methods do not have to be public.
@Configuration
class MyConfig {
@Autowired
void conversionService(GenericConversionService genericConversionService) {
genericConversionService.addConverter(String.class, UUID.class, UUID::fromString);
genericConversionService.addConverter(String.class, DateTime.class, DateTime::parse);
genericConversionService.addConverter(String.class, EnumState.class, EnumState::valueOf);
}
}
You can also add it dinamically using addConverter method on your DefaultConversionService-ish class:
DefaultConversionService cs = new <YourClassThatInheritsFromDefaultConversionService or DefaultConversionService>();
cs.addConverter(new MyConverter());
For anyone who stumbles on this now via a google search or similar 2+ years after the question was originally posted, adding converters has been made much easier through Java Config: WebMvcConfigurerAdapter
provides the addFormatters(FormatterRegistry)
method that can be used to specify additional custom converters.
While experimenting with different ways and even following spring source code in some i came across with an interesting thing.
The only way i found to use conversionService without overriding the existing converters with my custom ones was either to extend or re-implement the conversionService calling the super class's afterPropertiesSet() method to register the default converters and then add the custom ones.
But even if i was using that way, at runtime i was getting an exception that no converter was found for my specific types (e.g. from String to Logger).
That triggered my interest and i followed spring source code to find out why and i realized that spring was trying to find a custom converter registered with PropertyEditor. I am not sure why this is happening. I have to add here that my application is not using spring mvc and conversionService might somehow need to be registered and i didn't do it.
Finally, i solved the issue with registering a custom converter using Property editor. This documentation can be viewed as reference:
http://static.springsource.org/spring/docs/current/spring-framework-reference/html/validation.html
I would be very interested in knowing why Spring was not finding my registered custom converters in the conversionService's registry (or at least why spring was not looking at that registry to find the custom converters). Was i missing any configuration?
With spring > 4 it is no more necessary to implement an own derivation of the ConversionService. Initialize it in a @Configuration annotated class as follows:
@Configuration
public class ConversionServiceProvider
{
@Autowired
private MyConverterImpl myConverter;
@Bean
public ConversionService getConversionService()
{
ConversionServiceFactoryBean bean = new ConversionServiceFactoryBean();
bean.setConverters( getConverters() );
bean.afterPropertiesSet();
ConversionService object = bean.getObject();
return object;
}
private Set<Converter<?, ?>> getConverters()
{
Set<Converter<?, ?>> converters = new HashSet<Converter<?, ?>>();
converters.add( myConverter );
// add here more custom converters, either as spring bean references or directly instantiated
return converters;
}
}