I have a lot of Enums implementing an Interface called Codeable. I want to do a reverse look up when deserializing from json and trying to use a ConverterFactory
public class StringToCodeableConverterFactory implements ConverterFactory<String, Codeable> {
@Override
public <T extends Codeable> Converter<String, T> getConverter(
Class<T> targetType) {
return new StringToCodeableConverter<T>(targetType);
}
private final class StringToCodeableConverter<T extends Codeable> implements Converter<String, T> {
private Class<T> enumType;
public StringToCodeableConverter(Class<T> enumType) {
this.enumType = enumType;
}
@Override
public T convert(String source) {
return CodeableUtil.get(this.enumType, source);
}
}
}
Here's the spring config
<!-- Custom Converters from String to Java Type-->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="com.duetto.model.StringToCodeableConverterFactory" />
</list>
</property>
</bean>
<mvc:annotation-driven conversion-service="conversionService">
After some digging, I figured out Spring is taking the default StringToEnumConverterFactory instead of my StringToCodeableConverterFactory, why is it this way? How can I make my take precedence over the other one?
What I noticed happening was that the DefaultConversionService's defaults included a StringToEnumConversion which appears first in the service's List of possible converters. As such, mine was never being hit, and the standard Enum conversion was being attempted every time.
My workaround was to:
registry.removeConvertible(String.class, Enum.class) where registry is an instance of FormatterRegistryMyEnumType.class.isAssignableFrom(targetType)) and delegated to either my custom converter or the default string-to-enum converter depending on the resultNote this approach has several problems, among them: StringToEnumConverter is a package-private class so I had to copy-paste it into my own code base. Additionally, this can't be the desired approach to solving this problem; it isn't very "springy".
Would love to hear alternative answers for this.
Worth noting, I'm using Spring 3.2.6
I found a much cleaner way, note that I'm using annotation config rather than xml but the principals should be the same.
In Spring's documentation, I found:
GenericConversionService is a generic implementation designed to be explicitly configured, either programatically or declaratively as a Spring bean. DefaultConversionService is a subclass that pre-registers the common Converters in the core.converter package as a convenience.
So, I now have overrides configured as follows:
@Override
public FormattingConversionService mvcConversionService() {
// use FormattingConversionService here rather than GenericFormattingConversionService (the default)
// because it does not automatically register defaults
FormattingConversionService conversionService = new FormattingConversionService();
addFormatters(conversionService);
return conversionService;
}
@Override
protected void addFormatters(FormatterRegistry registry) {
// register custom enum handler first
registry.addConverterFactory(new MyCustomEnumConverterFactory());
// now add in spring's defaults
DefaultConversionService.addDefaultConverters(registry);
DefaultFormattingConversionService.addDefaultFormatters(registry);
}
Now everything's working and it feels significantly less hacky.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With