4
votes

Secton 65.3 of the spring boot manual indicates that I can replace the default ObjectMapper by providing my own. I am not using boot, just a spring WebMVC application that builds to a .war and runs in tomcat.

It instantiates my ObjectMapper but doesn't use it. I used the debugger to trace through why timestamps still come out as numeric and found that it was using a different instance of ObjectMapper. It's not clear to me where it came from, or why this doesn't cause it to only use mine:

    @Primary
@Bean
public ObjectMapper localObjectMapper() {
    JodaMapper mapper = new JodaMapper();
    mapper.setWriteDatesAsTimestamps(false);
    mapper.getSerializationConfig().with(SerializationFeature.INDENT_OUTPUT)
            .without(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS)
            .without(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS)
            .without(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

    return mapper;
}

The above is in a @Configure bean that's definitely getting loaded.

The approach I took above worked fine in Spring 3, just not when I ugpraded to 4.2.2. I have read Jackson Integration Improvements as well, and tried approaches listed there, to the same effect.

--Chris

2
Is JodaMapper your class that extends ObjectMapper? Do you have a WebMvcConfigurerAdapter where you register a MappingJackson2HttpMessageConverter? - Adam Michalik
JodaMapper is indeed a class that extends ObjectMapper, but I didn't write it - it is a built-in part of jackson-datatype-joda. It's a short subclass, mainly what it does is calls super() then registers new JodaModule() which in turn registers serializer/deserializers for the Joda types it supports. I do have a WebMvcConfigurerAdapter and I did register a MappingJackson2HttpMessagConverter. It didn't seem to make any difference, but should it have? Is that the mechanism by which spring will find an ObjectMapper? - wz2b
Did you ever get around this? - Robert Bain
@RobertBain did you ever get around this? - pinkpanther
@wz2b did you ever get around this? - pinkpanther

2 Answers

2
votes

The way I always did it was:

@Configuration
@EnableWebMvc
public class MyWebMvcConfigurer extends WebMvcConfigurerAdapter {

    @Bean
    public ObjectMapper localObjectMapper() {
        JodaMapper mapper = new JodaMapper();
        // ...
        return mapper;
    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(new MappingJackson2HttpMessageConverter (localObjectMapper())); // use your own ObjectMapper
    }
}

One warning, to quote the JavaDoc of WebMvcConfigurer.html#configureMessageConverters:

Note that adding converters to the list, turns off default converter registration. To simply add a converter without impacting default registration, consider using the method extendMessageConverters(java.util.List) instead.

0
votes

In Spring 4 I've solved with the following xml-configuration

<bean name="jacksonObjectMapper"
    class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
    <property name="featuresToDisable">
    <array>
        <util:constant
            static-field="com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS" />
    </array>
    </property>
</bean>

<mvc:annotation-driven>
    <mvc:message-converters register-defaults="true">
    <bean
        class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
        <property name="objectMapper" ref="jacksonObjectMapper" />
    </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

putting it in the Servlet configuration file, usually under

/WEB-INF/spring/appServlet/*.xml