How do I obtain the Jackson ObjectMapper in use by Spring 4.1?
JavaJsonSpringSpring MvcJacksonJava Problem Overview
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.
Java Solutions
Solution 1 - Java
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;
Solution 2 - Java
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.
Solution 3 - Java
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.
Solution 4 - Java
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.
Solution 5 - Java
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.
Solution 6 - Java
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;
Solution 7 - Java
A two-stepper if you will;
-
At your
@SpringBootApplication
class, add:@Bean public ObjectMapper mapper() { return new ObjectMapper(); }
-
Anywhere you wish to use
ObjectMapper
:@Autowired ObjectMapper mapper;
Peace!
Solution 8 - Java
An Update for Spring 4.3:
- As of Spring 4.3, classes with a single constructor can omit the @Autowired annotation
- Consequently, if you add a constructor which takes an ObjectMapper parameter it will be autowired with the Jackson ObjectMapper instance without needing to use the annotation @Autowired