0

My main question is: Where/when does Spring utilize (inject) the Jackson2ObjectMapperBuilderCustomizer bean defined in a project's @Configuration class -- can you please direct me to the line of code? The directions here make it seem like all I need to do is define that bean to control how responses are serialized in JSON, but it's not working -- i.e. I can't disable any of the SerializationFeatures.

Some background:

  • spring-boot 2.1.1 release
  • spring-webmvc-5.1.3.release
  • jackson 2.9.7

I have written a REST api (@RestController). I'm unable to customize the way Jackson serializes the Java Instant types in the http response. I have tried various combinations of defining an ObjectMapper bean, a MappingJackson2HttpMessageConverter bean, and also a Jackson2ObjectMapperBuilderCustomizer bean in my configuration (not all at once):

@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
  return builder -> {
     builder.modules(new JavaTimeModule());
     builder.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
     builder.featuresToDisable(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS);
  }
}

When I debug the application, it looks like the RequestMappinghandlerAdapter gets its converters initialized by WebMvcConfigurationSupport, but all those converters are instantiated manually instead of being injected. That is, all the MappingJackson2HttpMessageConverters are created with calls to `new MappingJackson2HttpMessageConverter()", which in turn simply creates stock Jackson2ObjectMapperBuilders and ObjectMappers:


// in org.springframework:spring-web:5.1.3.RELEASE:

public class MappingJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter {
  // ... more
  public MappingJackson2HttpMessageConverter() {
      this(Jackson2ObjectMapperBuilder.json().build());
  }
}

public class Jackson2ObjectMapperBuilder {
  public static Jackson2ObjectMapperBuilder json() {
    return new Jackson2ObjectMapperBuilder();
  }
}

The HttpEntityMethodProcessor that handles the response uses the same converters. I could not find where in this lifecycle the Jackson2ObjectMapperBuilderCustomizer performs the customization. I know I must have missed something, but I haven't been able to find it.

Tung
  • 5,334
  • 1
  • 34
  • 41

1 Answers1

1
@Bean
@Primary
public ObjectMapper customMapper(){
    ObjectMapper mapper = new ObjectMapper();
    mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    mapper.configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false);
    return mapper;
}

Put the above bean defintion in your configuration. This will make spring use this custom bean instead of the default one.

Karthik TU
  • 151
  • 1
  • 8
  • Yeah, I had already tried this as it's a popular suggestion online, but it didn't work for me. This is why I started to dig deeper into how all of this magically works. When I debug the application, the ObjectMapper being used was not the one that I had declared as "primary". – Tung Mar 04 '20 at 06:46
  • Is it a primary bean? – Karthik TU Mar 04 '20 at 16:10
  • Yes, I've tried marking it as a primary bean. At this point, my interest is less about trying to customize the serialization, and more about learning how some of supposed solutions to this work behind the scenes. – Tung Mar 05 '20 at 00:09