SpringMVC and @Configuration: register ConversionService and HttpMessageConverter
-
22-12-2019 - |
Question
I really like spring and the @Configuration style to get rid of xml based configuration. I successfully use it for the service and repository layer. What I also love is the dependency injection feature and the JDO/JPA/Jdbc utilities!
What I don't really get is, how the Spring WebMVC works. There is too much uncontrollable magic for me. (and with @EnableAutoConfiguration there is even more magic introduced. Good for easy prototyping, difficult to maintain).
That is how I configure my webapp:
public class SpringWebBooter implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigApplicationContext rootContext = new AnnotationConfigApplicationContext();
rootContext.register(SpringConfiguration.class); //main configuration class for all beans
rootContext.refresh();
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.setParent(rootContext);
ctx.register(SpringWebConfiguration.class); //web context configuration class
ServletRegistration.Dynamic api = servletContext.addServlet("api", new DispatcherServlet(ctx));
api.setLoadOnStartup(1);
api.addMapping("/api/*");
}
}
Now I want to add type converters and httpMessageConverters, so in the SpringWebConfiguration class I tried:
@EnableWebMvc
@Configuration
@ComponentScan
public class SpringWebConfiguration {
//works but feels very *magic*
@Autowired
public void configureConversionService(FormattingConversionService conversionService) {
conversionService.addConverter(new PointConverter(GEOMETRY_FACTORY));
conversionService.addConverterFactory(new StringToEnumConverterFactory());
}
//not working yet
@Bean
public MappingJackson2HttpMessageConverter createJsonMessageConverter() {
ObjectMapper o = new ObjectMapper();
o.enable(SerializationFeature.INDENT_OUTPUT);
MappingJackson2HttpMessageConverter c = new MappingJackson2HttpMessageConverter();
c.setObjectMapper(o);
return c;
}
}
What I'd rather find intuitive is to add type and message converters when I construct the dispatcher servlet. That would be much clearer than some dubious autowiring or bean creation. I always "hope" that the Dispatcher Servlet internally pics up my beans, but it is often just trial and error. Is it possible to set up spring Mvc in a directer way? With less magic and more concrete instantiations and #addHttpMessageConverter(...) calls for example?
Same basically for the ExceptionResolvers, RequestHandler and RequestAdapter.
Jan
Solution
The most direct way would be to extend WebMvcConfigurationSupport
. You can setup almost everything that way by overriding the methods.
But be aware that it is a very direct way to setup stuff. It gives you much more control than you have now or than even WebMvcConfigurerAdapter
would give you. From the docs:
If the customization options of {@link WebMvcConfigurer} do not expose
something you need to configure, consider removing the {@code @EnableWebMvc}
annotation and extending directly from {@link WebMvcConfigurationSupport}
overriding selected {@code @Bean} methods
Custom (or customized) message converters can be added by overriding configureMessageConverters
.
OTHER TIPS
If you extend the WebMvcConfigurerAdapter for your web configuration, it should feel a little less magic and also give you the hook to configure your message converters as well as a number of other components.
@Configuration
@ComponentScan
@EnableWebMvc
public class WebConfiguration extends WebMvcConfigurerAdapter
{
@Autowired
private CustomObjectMapper domainMapper;
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters)
{
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(domainMapper);
converters.add(converter);
super.configureMessageConverters(converters);
}
}