First of all ... Im relatively new in Spring, I use spring 3.x and I DONT LIKE SPRING\'S XML CONFIGURATION FILES ... I dont want for every refactoring I do, to run into XML
I am not sure if this works in Spring 3 but this is the solution for Spring 4:
@Configuration
@EnableWebMvc
class WebMvcContext extends WebMvcConfigurerAdapter {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new DateConverter("yyyy-MM-dd HH:mm:ss"));
//registry.addConverter(anotherConverter);
}
}
DateConverter is a custom converter:
public class DateConverter implements Converter<String, Date>{
private static final Logger LOGGER = LoggerFactory.getLogger(DateConverter.class);
private final String dateFormat;
private final SimpleDateFormat formatter;
public DateConverter(String dateFormatPattern) {
this.dateFormat = dateFormatPattern;
this.formatter = new SimpleDateFormat(dateFormatPattern);
}
@Override
public Date convert(String source) {
Date date = null;
try {
date = formatter.parse(source);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
}
Do the following:
@SpringBootApplication
@PropertySources({ @PropertySource("classpath:application.properties") })
public class YourApplication {
public static void main(String[] args) {
SpringApplication.run(YourApplication.class, args);
ConversionService conversionService = DefaultConversionService.getSharedInstance();
ConverterRegistry converters = (ConverterRegistry) conversionService;
converters.addConverter(new LocalDateToStringConverter());
}
}
Where LocalDateToStringConverter looks like this.
public class LocalDateToStringConverter implements Converter<LocalDate, String> {
@Override
public String convert(LocalDate localDate) {
try {
String date = localDate.format(DateTimeFormatter.ofPattern("dd-MM-yyyy"));
return date;
} catch(DateTimeParseException ex) {
}
return null;
}
}
With Spring MVC 3.2, you can create a conversion service class that extends the DefaultFormattingConversionService e.g
ApplicationConversionService.java
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.stereotype.Component;
@Component("conversionService")
public class ApplicationConversionService extends DefaultFormattingConversionService {
public ApplicationConversionService(){
//DefaultFormattingConversionService's default constructor
//creates default formatters and converters
super(); //no need for explicit super()?
//add custom formatters and converters
addConverter(new MyConverter());
}
}
and specify it in the spring config e.g
dispatcher-servlet.xml
<mvc:annotation-driven conversion-service="conversionService"/>
First you have to define an annotation: TypeConverter
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @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
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.
The approach outlined by @Ralph is neat, I have +1'd his answer. Let me also recommend an alternative approach which is using @Configuration support - essentially a way to configure Spring beans using Java instead of xml. With this approach the message converters can be registered this way:
@Configuration
@EnableWebMvc
@ComponentScan(...)
public class CustomConfig extends WebMvcConfigurerAdapter {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new EnumConverter());
converters.add(new FooConverter());
...
}
}