4

I have a single @RequestMapping that consumes a custom MIME type. The request uses an ObjectMapper bean defined in the @Configuration to enabled the JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER.

This feature allows typically invalid json (treating backslashes as a non-special character) to be consumed, which is a requirement of this particular @RequestMapping to allow google encoded polylines to be parsed directly. However this means that this ObjectMapper is now being used for ALL of my @RequestMapping when it is really only a requirement for one.

Is there a way to differentiate the ObjectMapper being used for each @Controller or @RequestMapping?

Object Mapper Bean

@Bean
public ObjectMapper objectMapper() {
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
    builder.featuresToEnable(
      JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER);

    return builder.build();
}

Request Mapping Interface Method

@ApiOperation(value = "Returns the toll cost breakdown for a journey", notes = "", response = TotalCost.class, tags={ "pricing", })
@ApiResponses(value = { 
    @ApiResponse(code = 200, message = "successful operation", response = TotalCost.class) })
@RequestMapping(value = "/pricing/journeyCost",
    produces = { "application/json" }, 
    consumes = { "application/vnd.toll-pricing+json" },
    method = RequestMethod.POST)
ResponseEntity<TotalCost> getTollBreakdownFromEncodedPoly(@ApiParam(value = "Request object representing the journey" ,required=true ) @RequestBody Journey body);
Jags
  • 1,639
  • 1
  • 16
  • 30

2 Answers2

3

I found the answer in another stackoverflow question linked to me by another user - https://stackoverflow.com/a/45157169/2073800

I just had to add the following @Bean to my @Configuration

@Bean
public HttpMessageConverters customConverters() {
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
    builder.featuresToEnable(
      JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER);

    final AbstractJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(builder.build());
    converter.setSupportedMediaTypes(Collections.singletonList(MediaType.valueOf("application/vnd.toll-pricing+json")));

    return new HttpMessageConverters(converter);
}
Jags
  • 1,639
  • 1
  • 16
  • 30
1

If you've a custom MIME type, then you can register a custom HttpMessageConverter that uses a special ObjectMapper for your MIME type, and returns false from canRead/canWrite for regular MIME types. You register your custom HttpMessageConverter like so:

@EnableWebMvc
@Configuration
@ComponentScan
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void configureMessageConverters(
      List<HttpMessageConverter<?>> converters) {

        messageConverters.add(myCustomMessageConverter());

        super.configureMessageConverters(converters);
    }
}

Think of it as related to content negotiation, and not related to URL mapping; URL mapping (@RequestMapping) is meant for finding a handler, not for choosing what marshaller/unmarshaller to use.

Abhijit Sarkar
  • 21,927
  • 20
  • 110
  • 219
  • Understanding content negotiation and a comment on my question pointed me in the right direction. I don't doubt the above solution would have worked, but I found something slightly easier. – Jags Jul 18 '17 at 22:26
  • @Jags I looked at what Szymon Stepniak had in the other thread, and it's exactly similar to what I said, except for the part how you register the converter. When you say you don't doubt the above would've worked, I doubt that you don't really understand what's going on. – Abhijit Sarkar Jul 18 '17 at 22:49
  • I don't disagree that your answers are similar, however his answer was much easier to follow and better explained. I also agree that I probably don't understand completely the intricacies, but maybe that is also a reflection on the quality of your answer? I applied your answer, and from my understanding I created a custom implement of a `HttpMessageConverter` and overrode the methods to only accept one `MediaType`. Szymons answer was much more succinct and straightforward. – Jags Jul 18 '17 at 22:59