Affects: 2.7.x

Configuration of Jackson is only done with this configuration class:

@Configuration
public class MiscConfig {

    @Bean
    public Jackson2ObjectMapperBuilderCustomizer builderCustomizer() {
        return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder
                .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    }
}

When the project is running request mapping is done as if the configuration is not applied.

When I autowire MappingJackson2HttpMessageConverter to some dummy component and run serialization by hand it works fine.

@Component
public class Dummy {
  private final MappingJackson2HttpMessageConverter c;

  public Dummy(MappingJackson2HttpMessageConverter c) {
    this.c = c;

    c.getObjectMapper().writeValueAsString(ZonedDateTIme.now()); // works fine
  }
}

When I dived into spring mvc configurations I saw this method in WebMvcConfigurationSupport

    @Bean
    public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
            @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
            @Qualifier("mvcConversionService") FormattingConversionService conversionService,
            @Qualifier("mvcValidator") Validator validator) {

        RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
        adapter.setContentNegotiationManager(contentNegotiationManager);
        adapter.setMessageConverters(getMessageConverters());
        adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer(conversionService, validator));
        adapter.setCustomArgumentResolvers(getArgumentResolvers());
        adapter.setCustomReturnValueHandlers(getReturnValueHandlers());
        ...
    }

    protected final List<HttpMessageConverter<?>> getMessageConverters() {
        if (this.messageConverters == null) {  // always is null at first run
            this.messageConverters = new ArrayList<>();
            configureMessageConverters(this.messageConverters);  // calls all WebMvcConfigurers which do nothing on this call
            if (this.messageConverters.isEmpty()) {
                addDefaultHttpMessageConverters(this.messageConverters); // creation of converter showed next line
                // new MappingJackson2HttpMessageConverter(Jackson2ObjectMapperBuilder.json().build())
            }
            extendMessageConverters(this.messageConverters); // calls all WebMvcConfigurers which do nothing on this call
        }
        return this.messageConverters;
    }
}

so it looks like only converter for json is default one

Only elegant workaround I've found is to insert autowired Converter inside converters list with the help of WebMvcConfigurer.extendMessageConverters

@Configuration
@EnableWebSecurity
@EnableWebMvc
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class Config implements WebMvcConfigurer  {
    private final MappingJackson2HttpMessageConverter jacksonConverter;

    public Config(MappingJackson2HttpMessageConverter jacksonConverter) {
        this.jacksonConverter = jacksonConverter;
    }

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(0, jacksonConverter);
    }
}

BUT in the RestTemplate everything is working fine because of the class HttpMessageConverters

Can you provide me some guidance is this bug or a feature?


Comment From: sbrannen

Thanks for getting in touch, but it feels like this is a question that would be better suited to Stack Overflow. As mentioned in the guidelines for contributing, we prefer to use the issue tracker only for bugs and enhancements. Feel free to update this issue with a link to the re-posted question (so that other people can find it) or add some more details if you feel this is a genuine bug.


The above is our standard policy. Having pointed that out, however, I can add the following.

Message converter configuration with the Spring Framework is documented in the reference manual.

Jackson2ObjectMapperBuilderCustomizer is a Spring Boot feature, not a Spring Framework feature. If you would like more information on that, feel free to use Google or similar search engines.