How to Configure Mappingjacksonhttpmessageconverter While Using Spring Annotation-Based Configuration

How to configure MappingJacksonHttpMessageConverter while using spring annotation-based configuration?

Use the WebMvcConfigurer.configureMessageConverters() method:

Configure the HttpMessageConverters to use [...] If no message converters are added to the list, default converters are added instead.

With @Configuration you have:

@Configuration
class MvcConf extends WebMvcConfigurationSupport {
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(converter());
addDefaultHttpMessageConverters(converters);
}

@Bean
MappingJacksonHttpMessageConverter converter() {
MappingJacksonHttpMessageConverter converter = new MappingJacksonHttpMessageConverter()
//do your customizations here...
return converter;
}
}

Call to addDefaultHttpMessageConverters() is required because the defaults are not applied when using custom converters.

IMPORTANT NOTE You must remove @EnableWebMvc for your converters to be configured if you extend WebMvcConfigurationSupport.

How to return serialized object using MappingJackson2HttpMessageConverter

I solved my issue thanks to this answer
https://stackoverflow.com/a/10650452/2010246

A

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

Will not work just like that even if I am overriding this method in AbstractDispatcherServletInitializer

Instead of that I had to create separate class for MVC configuration

package configuration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

import java.util.List;

@Configuration
public class Mvc extends WebMvcConfigurationSupport {
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(converter());
addDefaultHttpMessageConverters(converters);
}

@Bean
MappingJackson2HttpMessageConverter converter() {
return new MappingJackson2HttpMessageConverter();
}
}

Now it loads correctly and I can simply return the class like I wanted to

I guess the core problem was there were no class that is annotated as @Configuration and extends the WebMvcConfigurationSupport parent

How can we configure the internal Jackson mapper when using RestTemplate?

The default RestTemplate constructor registers a set of HttpMessageConverters:

this.messageConverters.add(new ByteArrayHttpMessageConverter());
this.messageConverters.add(new StringHttpMessageConverter());
this.messageConverters.add(new ResourceHttpMessageConverter());
this.messageConverters.add(new SourceHttpMessageConverter());
this.messageConverters.add(new XmlAwareFormHttpMessageConverter());
if (jaxb2Present) {
this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
}
if (jacksonPresent) {
this.messageConverters.add(new MappingJacksonHttpMessageConverter());
}
if (romePresent) {
this.messageConverters.add(new AtomFeedHttpMessageConverter());
this.messageConverters.add(new RssChannelHttpMessageConverter());
}

The MappingJacksonHttpMessageConverter in turns, creates ObjectMapper instance directly. You can either find this converter and replace ObjectMapper or register a new one before it. This should work:

@Bean
public RestOperations restOperations() {
RestTemplate rest = new RestTemplate();
//this is crucial!
rest.getMessageConverters().add(0, mappingJacksonHttpMessageConverter());
return rest;
}

@Bean
public MappingJacksonHttpMessageConverter mappingJacksonHttpMessageConverter() {
MappingJacksonHttpMessageConverter converter = new MappingJacksonHttpMessageConverter();
converter.setObjectMapper(myObjectMapper());
return converter;
}

@Bean
public ObjectMapper myObjectMapper() {
//your custom ObjectMapper here
}

In XML it is something along these lines:

<bean id="restOperations" class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<util:list>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"/>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper" ref="customObjectMapper"/>
</bean>
</util:list>
</property>
</bean>

<bean id="customObjectMapper" class="org.codehaus.jackson.map.ObjectMapper"/>

Note that the transition isn't really 1:1 - I have to explicitly create messageConverters list in XML while with @Configuration approach I could reference existing one and simply modify it. But this should work.

How to customize Jackson in Spring MVC (not Spring Boot) application

Ok, yes, this works as long as it's combined with @EnableWebMvc rather than <mvc:annotation-driven/>:

@EnableWebMvc
@Configuration
public class CustomWebConfiguration extends WebMvcConfigurerAdapter {

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

for (HttpMessageConverter<?> converter : converters) {
if (converter instanceof MappingJackson2HttpMessageConverter) {
((MappingJackson2HttpMessageConverter) converter).getObjectMapper().
enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
break;
}
}
}
}

Spring, Jackson and Customization (e.g. CustomDeserializer)

You don't say how you're using Jackson in Spring, so I'll assume you're using it through <mvc:annotation-driven/> and the @RequestBody and/or @ResponseBody annotations.

One of the things that <mvc:annotation-driven/> does is to register a AnnotationMethodHandlerAdapter bean which comes with a number of pre-configured HttpMessageConverter beans, including MappingJacksonHttpMessageConverter, which handles marshalling to and from Jackson-annotated model classes.

Now MappingJacksonHttpMessageConverter has a setObjectMapper() method, which allows you to override the default ObjectMapper. But since MappingJacksonHttpMessageConverter is created behind the scenes by <mvc:annotation-driven/>, you can't get to it.

However, <mvc:annotation-driven/> is just a convenient short-cut. It's just as a valid to declare your own AnnotationMethodHandlerAdapter bean, injecting into it your own MappingJacksonHttpMessageConverter bean (via the messageConverters property), and injecting your own customized ObjectMapper into that.

You then have the problem of how to build a custom ObjectMapper, since it's not a very Spring-friendly class. I suggest writing your own simple implementation of FactoryBean.

So you'd end up with something like this:

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper">
<bean class="com.x.MyObjectMapperFactoryBean"/>
</property>
</bean>
</property>
</bean>

Configuring ObjectMapper in Spring

Using Spring Boot (1.2.4) and Jackson (2.4.6) the following annotation based configuration worked for me.

@Configuration
public class JacksonConfiguration {

@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, true);

return mapper;
}
}

Spring web-app annotation driven - How to configure? (Best Practice)

There is nothing wrong with this approach. Folks prefer it this way. So, go with it, I would say.



Related Topics



Leave a reply



Submit