In Spring MVC, it's common to configure the ObjectMapper used by Jackson to customize the JSON output. This can be done by implementing WebMvcConfigurer interface and overriding the configureMessageConverters() method, as shown in the code below.

@Configuration
@EnableWebMvc
public class WebConfiguration implements WebMvcConfigurer {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
                .simpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS")
                .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
        converters.add(new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build()));
    }
}

However, overriding configureMessageConverters() method will remove all default converters added by Spring MVC. If your controllers support other media types like text/plain, these controllers will return 415 Unsupported Media Type error.

It's better to only replace Jackson converters in the list. As shown in the code below, we should override extendMessageConverters() method and replace both MappingJackson2HttpMessageConverter and MappingJackson2XmlHttpMessageConverter converters in the list. By doing this, we keep all the default converters.

@Configuration
@EnableWebMvc
public class WebConfiguration implements WebMvcConfigurer {

    @Override
    public void extendMessageConverters(final List<HttpMessageConverter<?>> converters) {
        final Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
                .simpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS")
                .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        this.updateConverter(converters, new MappingJackson2HttpMessageConverter(builder.build()));
        this.updateConverter(converters, new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build()));
    }

    private void updateConverter(final List<HttpMessageConverter<?>> converters, final HttpMessageConverter<?> converter) {
        int index = -1;
        for (int i = 0; i < converters.size(); i++) {
            if (converter.getClass().isInstance(converters.get(i))) {
                index = i;
                break;
            }
        }
        if (index != -1) {
            converters.set(index, converter);
        } else {
            converters.add(converter);
        }
    }
}