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:


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"/>

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{

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

    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:
    extend: '',
    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

Jackson JSON Processing:
Jackson Date Handling FAQ:
Some ideas from this blog entry:
Date type in Ext-JS:!/api/Ext.Date

No comments:

Post a Comment