How to customise the Jackson JSON mapper implicitly used by Spring Boot?

193,968

Solution 1

You can configure property inclusion, and numerous other settings, via application.properties:

spring.jackson.default-property-inclusion=non_null

There's a table in the documentation that lists all of the properties that can be used.

If you want more control, you can also customize Spring Boot's configuration programatically using a Jackson2ObjectMapperBuilderCustomizer bean, as described in the documentation:

The context’s Jackson2ObjectMapperBuilder can be customized by one or more Jackson2ObjectMapperBuilderCustomizer beans. Such customizer beans can be ordered (Boot’s own customizer has an order of 0), letting additional customization be applied both before and after Boot’s customization.

Lastly, if you don't want any of Boot's configuration and want to take complete control over how the ObjectMapper is configured, declare your own Jackson2ObjectMapperBuilder bean:

@Bean
Jackson2ObjectMapperBuilder objectMapperBuilder() {
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
    // Configure the builder to suit your needs
    return builder;
}

Solution 2

I am answering bit late to this question, but someone, in future, might find this useful. The below approach, besides lots of other approaches, works best, and I personally think would better suit a web application.

@Configuration
@EnableWebMvc
public class WebConfiguration extends WebMvcConfigurerAdapter {

 ... other configurations

@Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
        builder.serializationInclusion(JsonInclude.Include.NON_NULL);
        builder.propertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
        builder.serializationInclusion(Include.NON_EMPTY);
        builder.indentOutput(true).dateFormat(new SimpleDateFormat("yyyy-MM-dd"));
        converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
        converters.add(new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build()));
    }
}

Solution 3

The documentation states several ways to do this.

If you want to replace the default ObjectMapper completely, define a @Bean of that type and mark it as @Primary.

Defining a @Bean of type Jackson2ObjectMapperBuilder will allow you to customize both default ObjectMapper and XmlMapper (used in MappingJackson2HttpMessageConverter and MappingJackson2XmlHttpMessageConverter respectively).

Solution 4

A lot of things can configured in applicationproperties. Unfortunately this feature only in Version 1.3, but you can add in a Config-Class

@Autowired(required = true)
public void configureJackson(ObjectMapper jackson2ObjectMapper) {
    jackson2ObjectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
}

[UPDATE: You must work on the ObjectMapper because the build()-method is called before the config is runs.]

Solution 5

You can add a following method inside your bootstrap class which is annotated with @SpringBootApplication

    @Bean
    @Primary
    public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
    ObjectMapper objectMapper = builder.createXmlMapper(false).build();
    objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    objectMapper.configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false);

    objectMapper.registerModule(new JodaModule());

    return objectMapper;
}
Share:
193,968

Related videos on Youtube

Jonik
Author by

Jonik

I'm a generalist software developer who's been programming professionally for 15+ years. Simplicity, code maintainability, easy deployments, automated testing, and continuous integration are some of the things close to my heart as a developer. I currently work as a freelance developer, focused on backend (Java/Scala/JVM mostly) and Android development. Enjoying Kotlin and Jetpack Compose nowadays especially! You can reach me by email through &lt;jonik at iki dot country code for finland&gt;.

Updated on March 10, 2022

Comments

  • Jonik
    Jonik about 2 years

    I'm using Spring Boot (1.2.1), in a similar fashion as in their Building a RESTful Web Service tutorial:

    @RestController
    public class EventController {
       @RequestMapping("/events/all")
       EventList events() {
           return proxyService.getAllEvents();
       }
    }
    

    So above, Spring MVC implicitly uses Jackson for serialising my EventList object into JSON.

    But I want to do some simple customisations to the JSON format, such as:

    setSerializationInclusion(JsonInclude.Include.NON_NULL)
    

    Question is, what is the simplest way to customise the implicit JSON mapper?

    I tried the approach in this blog post, creating a CustomObjectMapper and so on, but the step 3, "Register classes in the Spring context", fails:

    org.springframework.beans.factory.BeanCreationException: 
      Error creating bean with name 'jacksonFix': Injection of autowired dependencies failed; 
      nested exception is org.springframework.beans.factory.BeanCreationException: 
      Could not autowire method: public void com.acme.project.JacksonFix.setAnnotationMethodHandlerAdapter(org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter); 
      nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: 
      No qualifying bean of type [org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter]   
      found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
    

    It looks like those instructions are for older versions of Spring MVC, while I'm looking for a simple way to get this working with latest Spring Boot.

    • sven.kwiotek
      sven.kwiotek over 9 years
      Do you have this Annotation inserted?: @SuppressWarnings({"SpringJavaAutowiringInspection"})
    • Constantino Cronemberger
      Constantino Cronemberger about 5 years
      Notice that if you are using Spring Web as well you will need to tell it manually to use this ObjectMapper otherwise it will create it own instance which will not be configured. See stackoverflow.com/questions/7854030/…
  • Jonik
    Jonik over 9 years
    Alright, this seems to work. Where would you put such a method? Perhaps in a main Application class (with @ComponentScan, @EnableAutoConfiguration etc)?
  • Andy Wilkinson
    Andy Wilkinson over 9 years
    Yes. This method can go in any @Configuration class in your app. The main Application class is a good place for it.
  • Andy Wilkinson
    Andy Wilkinson over 9 years
    The downside to this approach is that your custom configuration won't be applied to any ObjectMapper instances that are created or configured by Spring Boot.
  • Jonik
    Jonik over 9 years
    Hmm, the custom config is used for the implicit serialisation in @RestController classes which currently suffices for me. (So you mean those instances are created by Spring MVC, not Spring Boot?) But if I run into other cases where ObjectMappers need to be instantiated, I'll keep the Jackson2ObjectMapperBuilder approach in mind!
  • gaoagong
    gaoagong almost 9 years
    Important note: The Jackson2ObjectMapperBuilder class is part of the spring-web component and was added in version 4.1.1.
  • herau
    herau over 8 years
    @AndyWilkinson With this configuration, you can't use anymore Spring boot auto-configuration for Jackson isn't it ?
  • Andy Wilkinson
    Andy Wilkinson over 8 years
    @herau Correct. If you're happy using a milestone, Spring Boot 1.3 adds support for configuring serialisation inclusion via application.properties: github.com/spring-projects/spring-boot/commit/…
  • Dimitri Kopriwa
    Dimitri Kopriwa almost 8 years
    @Deprecated setSerializationInclusion
  • so-random-dude
    so-random-dude almost 7 years
    Deprecated: ObjectMapper.setSerializationInclusion was deprecated in Jackson 2.7 ... use stackoverflow.com/a/44137972/6785908 spring.jackson.default-property-inclusion=non_null instead
  • Nestor Milyaev
    Nestor Milyaev over 6 years
    That was the solution that saved my day. Except I did add this method to the REST controller itself, rather than to the configuration class.
  • GuiRitter
    GuiRitter about 6 years
    "If you're using an earlier version of Spring Boot" made me believe it wouldn't work with Spring Boot 2.0.1, but it worked. Thanks!
  • soufrk
    soufrk almost 6 years
    How to do the same without replacing the default ObjectMapper ? I mean keeping the default as well a custom.
  • Richtopia
    Richtopia about 5 years
    This one worked for me using Boot 2.1.3. The spring.jackson properties had no effect.
  • João Pedro Schmitt
    João Pedro Schmitt over 4 years
    In recent version you must implement WebMvcConfigurer
  • Somal Somalski
    Somal Somalski almost 4 years
    yes, peoples, try this solution, I've tried to provide Bean for ObjectMapper, then Bean for Jackson2ObjectMapperBuilder buy that didn't work and I still have no idea why. Appending coverter worked!
  • Michael
    Michael over 3 years
    I am having a problem with this approach of configuring the ObjectMapper in Spring Boot. Spring Boot does its own configuration of the ObjectMapper with its own Serializers/Deserializers for e.g. LocalDateTime. When defining your own Jackson2ObjectMapperBuilder you are loosing this Spring configuration.
  • M. Justin
    M. Justin over 3 years
    There are more properties than just the six mentioned in the linked "How-to" guide. A full list is available a the reference documentation appendex (currently eleven spring.jackson.* options are mentioned).