Sunday, January 1, 2012

Ext-JS, Json - Date/time mapping in Spring MVC with Jackson

The default date/time handling with Jackson and Spring is:

  • To serialize dates as a Unix epoch time - number of millseconds since Jan 1, 1970 (UTC). 
  • To always use GMT as the timezone, irrespective of the default timezone on the server. 

I prefer to see the dates in a string format with ISO-8601 standard. The way to handle this in Spring MVC with version 3.1 of the Spring framework is to provide a custom Jackson ObjectMapper, to handle the date serialization differently. A custom Object Mapper would be along these lines:

import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig.Feature;

public class CustomObjectMapper extends ObjectMapper {
    public CustomObjectMapper(){
        super.configure(Feature.WRITE_DATES_AS_TIMESTAMPS, false);
    }
}

Now Spring 3.1 has made it really simple to register this Custom Object Mapper with the Handler Adapters:
<mvc:annotation-driven > 
    <mvc:message-converters register-defaults="false">
        <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" >
            <property name="objectMapper">
                <bean class="org.bk.simplygtd.web.spring.CustomObjectMapper"/>
            </property>
        </bean>
    </mvc:message-converters>
 </mvc:annotation-driven>

Prior to Spring 3.1, a way to register this Custom Object Mapper would have been to write a custom BeanPostProcessor, to iterate through the handler adapters, find the relevant message converter(MappingJacksonHttpMessageConverter) and register the custom object mapper, something along these lines:
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter;
import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter;

public class CustomObjectMapperBeanPostProcessor implements BeanPostProcessor{

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof AnnotationMethodHandlerAdapter){
            AnnotationMethodHandlerAdapter methodHandlerAdapter = (AnnotationMethodHandlerAdapter)bean;
            for (HttpMessageConverter<?> messageConverter: methodHandlerAdapter.getMessageConverters()){
                if (messageConverter instanceof MappingJacksonHttpMessageConverter){
                    ((MappingJacksonHttpMessageConverter)messageConverter).setObjectMapper(new CustomObjectMapper());
                }
            }
        }
        return bean;
    }
}

Now the json responses from Spring MVC should be formatted correctly in this format: 2011-12-06T00:00:00.000+0000


If the user interface is using created using Ext-JS, the model for Ext-JS can be customized to use this date format along these lines - date format of 'c' indicates that the date string should be interpreted using ISO-8601 standard:
Ext.define('CUSTOM.model.Proj',{
    extend: 'Ext.data.Model',
    fields:[{name:'id', type:'string'},{name:'name', type:'string'}, 
            {name:'startDate', type:'date', dateFormat:'c'}, {name:'completedDate', type:'date', dateFormat:'c'},
            {name:'isDone', type:'boolean'}, {name:'version', type:'string'}]
});

There is still one problem, when submitting this date Ext-JS still does not format the date string correctly - it would, by default, send the date without the timezone offset(eg. 2011-12-25T00:15:00), which would be interpreted by the JSON deserializer as  a GMT date/time. To fix this just have this global function:

Ext.JSON.encodeDate = function(o)
{
   return '"' + Ext.Date.format(o, 'c') + '"';
};

Now the dates should be correctly posted to the server with timezone offsets also eg. 2011-12-25T01:15:00-05:00



References:
Jackson JSON Processing: http://jackson.codehaus.org/
Jackson Date Handling FAQ: http://wiki.fasterxml.com/JacksonFAQDateHandling
Some ideas from this blog entry: http://magicmonster.com/kb/prg/java/spring/webmvc/jackson_custom.html
Date type in Ext-JS: http://docs.sencha.com/ext-js/4-0/#!/api/Ext.Date


No comments:

Post a Comment