Custom Jackson Config for Spring Boot

Spring Boot comes with some really great and usually sensible defaults for creating a Spring Application, but sometimes these defaults need to be tweaked slightly. I recently found myself needing to change some of the Jackson settings, but only for Web Requests. We wanted to use snake_case for the JSON fields in our request and response bodies.

The simplest way to solve this is to just create a custom ObjectMapper bean which would get picked up automatically by Spring Boot. This can be accomplished by doing something like the following:

@Configuration
public class JacksonConfig {

  @Autowired
  public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
    ObjectMapper objectMapper = builder.createXmlMapper(false).build();

    // Some other custom configuration for supporting Java 8 features
    objectMapper.registerModule(new Jdk8Module());
    objectMapper.registerModule(new JavaTimeModule());

    // Use property
    objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);

    return objectMapper;
  }
}

The issue with this approach is that it will change the default ObjectMapper for the rest of the application. We only want to change it for Spring MVC. To make a change, we will need to extend the WebMvcConfigurerAdapter:

@EnableWebMvc
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {

  @Autowired
  private ObjectMapper objectMapper;

  @Override
  public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    ObjectMapper webObjectMapper = objectMapper.copy();
    webObjectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
    converters.add(new MappingJackson2HttpMessageConverter(webObjectMapper));
  }
}

Here we have injected the existing ObjectMapper and created a copy. On that copy we are able to set the desired property naming strategy (and any other configuration) and then added a custom message converter with it.

If you have not defined your own ObjectMapper bean, then the default one will be injected (see JacksonAutoConfiguration)

Spring Filter Ordering

The internet is littered with examples of how to add Cross Origin Resource Sharing (CORS) support to a Spring Boot application. Almost all of these examples use the SimpleCORSFilter which looks something like this:

@Component
public class SimpleCORSFilter implements Filter {

   	public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
       	HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin", "*");
   	    response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
       	response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Authorization, Origin, x-requested-with, Content-Type, Accept");
   	    chain.doFilter(req, res);
    }
   	public void init(FilterConfig filterConfig) {}
    public void destroy() {}
}

When working on an AngularJS project, I got stuck trying to determine why my requests were failing the CORS check but my filter was never being called.

After some investigation I found that Spring Security had its own filter that ended the FilterChain when authentication failed. I wasn’t passing the authentication header in the OPTIONS request and so when Spring Security couldn’t authorize the request, the rest of the chain stopped and thus never got to my filter.

As of Spring 2.5, fixing this issue is quite simple. Just add the @Order annotation to the filter like so:

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SimpleCORSFilter implements Filter {

The JavaDoc for @Order states:

The default value is Ordered.LOWEST_PRECEDENCE, indicating lowest priority (losing to any other specified order value).

Unless you pass the Oredered.HIGHEST_PRECEDENCE (or some other integer), the filter will be towards the end of the chain.