Register converters and converterFactories with annotations in Spring 3 Register converters and converterFactories with annotations in Spring 3 xml xml

Register converters and converterFactories with annotations in Spring 3


Spring does not have annotation support for Converters, but you can build your own.

All you need is an custom qualifier annotation (lets call it @AutoRegistered ) and some kind of Converter/Formatter Registrar (implements FormatterRegistrar) that registers all the Spring Beans with this @AutoRegistered annotation (and some xml to register this registration service).

Then you need to annotate your conveter with this annotation (and some other annotation to make it a spring bean) and that is all.

@AutoRegistered annotation:

@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE })@Retention(RetentionPolicy.RUNTIME)@Qualifierpublic @interface AutoRegistered {}

Registration service:

import java.util.List;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.core.convert.converter.Converter;import org.springframework.format.FormatterRegistrar;import org.springframework.format.FormatterRegistry;public class AutoregisterFormatterRegistrar implements FormatterRegistrar {    /**     * All {@link Converter} Beans with {@link AutoRegistered} annotation.     * If spring does not find any matching bean, then the List is {@code null}!.     */    @Autowired(required = false)    @AutoRegistered    private List<Converter<?, ?>> autoRegisteredConverters;    @Override    public void registerFormatters(final FormatterRegistry registry) {        if (this.autoRegisteredConverters != null) {            for (Converter<?, ?> converter : this.autoRegisteredConverters) {                registry.addConverter(converter);            }        }    }}

XML configuration for the registrar:

<bean id="applicationConversionService"    class="org.springframework.format.support.FormattingConversionServiceFactoryBean">    <property name="formatterRegistrars">        <set>            <bean                class="AutoregisterFormatterRegistrar"                autowire="byType" />        </set>    </property></bean>

BTW for your enum converter you do not need a ConversionFactory - a simple converter is enough:

@AutoRegistered@Componentpublic class EnumConverter implements Converter<Enum<?>, String> {    /** Use the same immutable value instead of creating an new array every time. */    private static final Object[] NO_PARAM = new Object[0];    /** The prefix of all message codes. */    private static final String PREFIX = "label_";    /** The separator in the message code, between different packages        as well as between package can class. */    private static final String PACKAGE_SEPARATOR = "_";    /** The separator in the message code, between the class name        and the enum case name. */    private static final String ENUM_CASE_SEPARATOR = "_";    /** The message source. */    private MessageSource messageSource;    @Autowired    public EnumConverter(final MessageSource messageSource) {        if (messageSource == null) {            throw new RuntimeException("messageSource must not be null");        }        this.messageSource = messageSource;    }    @Override    public String convert(final Enum<?> source) {        if (source != null) {            String enumValueName = source.name();            String code = PREFIX + source.getClass().getName().toLowerCase().                  replace(".", PACKAGE_SEPARATOR)            + ENUM_CASE_SEPARATOR + enumValueName.toLowerCase();            String message = messageSource.getMessage(code, NO_PARAM, enumValueName,                                                  LocaleContextHolder.getLocale());             return message;         } else {            return "";         }     }   }


Automatic registration of Converter beans is also provided by Spring Boot when @EnableAutoConfiguration is turned on - see Spring Boot features. It appears that no additional annotations (other than marking each converter bean as a @Component) is required for this.


First you have to define an annotation: TypeConverter

@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Componentpublic @interface TypeConverter {}

Then you have to register the conversion service and add all of the beans that have the annotation. This will be done with the following post processor:

public class ConverterRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {    registry.registerBeanDefinition("conversionService", BeanDefinitionBuilder.rootBeanDefinition(ConversionServiceFactoryBean.class).getBeanDefinition());}public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {    Map<String, Object> beansWithAnnotation = beanFactory.getBeansWithAnnotation(TypeConverter.class);    Collection converters = beansWithAnnotation.values();    DefaultConversionService conversionService = (DefaultConversionService) beanFactory.getBean("conversionService");    for (Object converter : converters) {        conversionService.addConverter((Converter<?, ?>) converter);    }}}

If you need more details check this blog entry