66
votes

Spring 4.1 instantiates a Jackson ObjectMapper instance. I have reason to want to @Autowire that instance into one of my controllers: The controller does some minor JSON parsing of its own using Jackson, but the ObjectMapper it uses should be the one and same instance that Spring itself is using. How do I go about accomplishing that?

Note that I'm not asking how to custom configure the ObjectMapper in use by Spring; I'm happy with the defaults. I just want to fish the instance used by Spring out so that I can re-use the existing instance in my own code.

7
Are you sure it creates a bean that can be Autowired and not local instances of ObjectMapper? If yes, can't this be fetched from the 'load bean from Context of type ObjectMapper.class'?TJ-
Adding an @Autowire property of type ObjectMapper in the controller is not enough. Apparently, Spring does not expose it as a standard bean.Adam Maass
In test environment I get it by adding @Autowired on ObjectMapper and @JsonTest on test classLu55

7 Answers

50
votes

If you're using Spring Boot with Jackson on your classpath and default implementation for JSON parsing in your REST controller, then this should work:

@Autowired
private ObjectMapper jacksonObjectMapper;
22
votes

As was said by others, you can't @Autowired it in directly into your controller.

@Emerson Farrugia's suggestion to create a new instance using

Jackson2ObjectMapperBuilder.json().build()

also didn't work for me because the obtained instance was not following the spring.jackson.* configuration properties, which I needed it to.


The solution I found was to obtain the ObjectMapper from Spring's MappingJackson2HttpMessageConverter which is injectable.

So I autowired it:

@Autowired
private MappingJackson2HttpMessageConverter springMvcJacksonConverter;

and then get the ObjectMapper from it like this:

ObjectMapper objectMapper = springMvcJacksonConverter.getObjectMapper();

This instance behaves exactly as Spring MVC's own message conversion - it probably is the same instance anyway.

18
votes

If you take a look at MappingJackson2HttpMessageConverter, you'll see that it creates a new ObjectMapper, but doesn't expose it as a bean. There's a getter, but the only way I've fished it out in the past is when I created the MappingJackson2HttpMessageConverter myself, e.g.

public class WebMvcConfiguration extends WebMvcConfigurerAdapter {

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

        MappingJackson2HttpMessageConverter jacksonMessageConverter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = jacksonMessageConverter.getObjectMapper();

        objectMapper.registerModule(new JodaModule());
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true);

        converters.add(jacksonMessageConverter);
    }
}

If you're working with Spring Boot, there's a section in the manual dedicated to working with the ObjectMapper If you create a default Jackson2ObjectMapperBuilder @Bean, you should be able to autowire that same ObjectMapper instance in your controller.

12
votes

The ObjectMapper is created by Jackson2ObjectMapperBuilder, and you can inject the builder using:

@Autowired
private Jackson2ObjectMapperBuilder mapperBuilder;

Then use mapperBuilder.build() to build an ObjectMapper instance, and this instance can use configurations in application.properties. Official doc here.

4
votes

I have debugged into source code of Spring Boot and found that only when we launch the whole context Jackson2ObjectMapperBuilder will contain the config we put in application.yml.

This means, if we want to generate an ObjectMapper in a Spring Boot test, with JUnit 5, we have to:

@ExtendWith(SpringExtension.class)
@SpringBootTest
class SomeTest {
    @Autowired
    private Jackson2ObjectMapperBuilder builder;
    ...

    @Test
    void testObjectMapper() {
        ObjectMapper mapper = builder.build();


    }

We cannot only make @SpringBootTest(classes = Jackson2ObjectMapperBuilder.class) to generate this builder.

When we bootRun we don't have this problem.

The configuration is set in Jackson2ObjectMapperBuilderCustomizerConfiguration#customize(Jackson2ObjectMapperBuilder builder) method.

enter image description here

1
votes

A two-stepper if you will;

  1. At your @SpringBootApplication class, add:

    @Bean
    public ObjectMapper mapper() {
      return new ObjectMapper();
    }
    
  2. Anywhere you wish to use ObjectMapper:

    @Autowired
    ObjectMapper mapper;
    

Peace!

1
votes

When you try to @Autowire the MappingJackson2HttpMessageConverter it gives you: No qualifying bean of type 'org.springframework.http.converter.json.MappingJackson2HttpMessageConverter' available: expected single matching bean but found 4: mappingJackson2HttpMessageConverter,jacksonHttpMessageConverter,halJacksonHttpMessageConverter,alpsJsonHttpMessageConverter.

This is not a big issue, you can just change your variable name to one of the above to get that instance: @Autowired private MappingJackson2HttpMessageConverter halJacksonHttpMessageConverter;