Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom Spring HttpMessageConverter not being used by the framework

I have a Spring mvc @RestController class where the method parameter is annotated with @RequestBody. Something like this:

@RestController
@RequestMapping("/features")
public class FeatureController {

    @PostMapping
    public Feature createFeature(@RequestBody Feature feature) {
         ......
    }
}

My Feature class has a private constructor built using a Builder pattern. So I created HttpMessageConverter called FeatureConverter and registered it properly using extendMessageConverters. The converter uses Jackson to parse the JSON and then uses Feature.Builder to create an instance of Feature.

My problem is that Spring registers an instance of MappingJackson2HttpMessageConverter before my custom FeatureConverter. As a result the parsing is attempted by MappingJackson2HttpMessageConverter even before it can reach FeatureConverter. Since the constructor is private so MappingJackson2HttpMessageConverter fails.

My question is how do I change the order so that FeatureConverter is asked before MappingJackson2HttpMessageConverter. Is there a proper way of doing it?

like image 831
sshekhar1980 Avatar asked Oct 15 '25 04:10

sshekhar1980


1 Answers

Spring MVC WebMvcConfigurerAdapter initialize HttpMessageConverters like that:

protected final List<HttpMessageConverter<?>> getMessageConverters() {
    if (this.messageConverters == null) {
        this.messageConverters = new ArrayList<HttpMessageConverter<?>>();
        configureMessageConverters(this.messageConverters);
        if (this.messageConverters.isEmpty()) {
            addDefaultHttpMessageConverters(this.messageConverters);
        }
        extendMessageConverters(this.messageConverters);
    }
    return this.messageConverters;
}

See: Github - WebMvcConfigurationSupport

As you can see there is 3 method:

  1. configureMessageConverters, empty by default it's where you are suppose to add converters
  2. addDefaultHttpMessageConverters, where as the name said will create all default converters, the default MappingJackson2HttpMessageConverter is created there.
  3. extendMessageConverters which as the documentation:

Override this method to extend or modify the list of converters after it has been configured. This may be useful for example to allow default converters to be registered and then insert a custom converter through this method.

Is to use when you want to modify the list after having all the defaults converter added.

To answer your question, if you don't need defaults converters you just have to Override configureMessageConverters and add it:

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    converters.add(new FeatureConverter());
}

If you need them you can either copy-paste the addDefaultHttpMessageConverters content and add it into configureMessageConverters and play with the order of initialisation there (ugly solution).

Otherwise you can use extendMessageConverters to add it after the default initialization and play with the order:

@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
    converters.add(the_index_you_want, new FeatureConverter()); 
}
like image 95
Baptiste Beauvais Avatar answered Oct 18 '25 22:10

Baptiste Beauvais