Feras Odeh
Feras Odeh

Reputation: 9296

Grails JSON Marshaller Shows a Different Date value than Original Date

In my Grails app, the original date read from the database is equal to:

{ endDate=2015-10-19 19:00:00.0}

While the JSON result is:

{"endDate": "2015-10-19T16:00:00Z"}

I think this is maybe related to time zone conversion. How could I show the original date without any timezone conversions in JSON?

Upvotes: 2

Views: 728

Answers (3)

uchamp
uchamp

Reputation: 2512

Working on an old application that is built with grails 2.3.11 in which for some unbeknownst reason @Dónal's solution wasn't working. Fortunately, I found an easier/more straightforward approach to register a custom marshaller on mrhaki's blog.

So, I made a copy of the default DateMarshaller that resides in org.codehaus.groovy.grails.web.converters.marshaller.json and modified the date formatter in my custom DateMarshaller and then registered the marshaller using the snippet below, taken from mrhaki's post.

dateMarshaller(ObjectMarshallerRegisterer) {
    // Assign custom marshaller instance.
    marshaller = new DateMarshaller()

    // Set converter class type.
    converterClass = JSON

    // Optional set priority. Default value is 0.
    priority = 1
}

Just make sure that your Custom Marshaller has a higher priority than the default one. Works like a charm!

Upvotes: 0

Dónal
Dónal

Reputation: 187499

Depending on which time zone you're in, 2015-10-19 19:00:00.0 and 2015-10-19T16:00:00Z may not be different times, they may be just different representations of the same time (instant).

In my case, I use a custom marshaller to ensure that times in my API's JSON response always use the UTC time zone. My custom marshaller looks like this:

import org.springframework.stereotype.Component

@Component
class DateMarshaller implements CustomMarshaller {

    @Override
    def getSupportedTypes() {
        Date
    }

    @Override
    Closure getMarshaller() {
        { Date date ->

            TimeZone tz = TimeZone.getTimeZone('UTC')
            date?.format("yyyy-MM-dd'T'HH:mm:ss'Z'", tz)
        }
    }
}

Remember to register the package this marshaller is in for Spring bean scanning in Config.groovy. The interface it implements is:

interface CustomMarshaller {

    /**
     * Indicates the type(s) of object that this marshaller supports
     * @return a {@link Class} or collection of {@link Class} 
     * if the marshaller supports multiple types
     */
    def getSupportedTypes()

    Closure getMarshaller()
}

Then I have a service that registers all my instances of CustomMarshaller for the relevant type(s):

import grails.converters.JSON
import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationContextAware

import javax.annotation.PostConstruct

class MarshallerRegistrarService implements ApplicationContextAware {

    static transactional = false

    ApplicationContext applicationContext

    // a combination of eager bean initialization and @PostConstruct ensures that the marshallers are registered when
    // the app (or a test thereof) starts
    boolean lazyInit = false

    @PostConstruct
    void registerMarshallers() {

        Map<String, CustomMarshaller> marshallerBeans = applicationContext.getBeansOfType(CustomMarshaller)

        marshallerBeans.values().each { CustomMarshaller customMarshaller ->

            customMarshaller.supportedTypes.each { Class supportedType ->
                JSON.registerObjectMarshaller supportedType, customMarshaller.marshaller
            }
        }
    }
}

This is a fairly involved solution, but In my case I'm using Grails 2.5.X. If I was using Grails 3.X I'd try to use JSON views instead.

Upvotes: 5

Seva
Seva

Reputation: 2488

If my memory is correct, JSON spec does not actually define a format for date format. But everybody uses ISO 8601, so it sort of de-facto standard. And most just always use Zulu time zone.

I searched myself some time ago, on ways to force Grails JSON to render dates in certain time zone, but failed. In my Grails web app, I just declare date fields as text and format them to proper time zone and format in my own code. On the good side, it also has an added benefit that you can guarantee it to stay that way in future. (I'm, using Grails since about 1.1 and did see breaking changes on several occasions.)

Upvotes: 0

Related Questions