Tuesday, March 29, 2011

Ext JS/Core and formatting date for Grails backend - reloaded

Here's the ultimate solution for modern browsers (works in FireFox and Chrome, there's a fix for IE):
Ext.util.JSON.encodeDate = function(o) { return JSON.stringify(o); }
I feel this needs some explanation :D So here it is:

The JSON object in modern browsers is a serializer/deserializer for JSON format. It uses all the necessary stuff (like the UTC version of date methods and adds the "Z" at the end denoting that this in fact is a Zulu time).

What about Internet Explorer? Well... There's this "fix" for this browser called json2.js. You can download it at https://github.com/douglascrockford/JSON-js/raw/master/json2.js.

The beauty of this solution however lies in the fact that it's an extremely fast solution because the browser's manufacturers are in fact able to provide an optimized version of the stringify and parse methods!

9 comments:

mistaecko said...

Great post (or series of posts ;)). Can you shed some light on how to correctly bind the date on the server (grails). I am using your rest-api-plugin. The date String always gets parsed to a java.sql.Timestamp instead of a date. Subsequently validation fails in line 'data.result.data.validate()' in JsonRestApiController. The unmarshalled value is correct, but not the type. Which is so weird because the target type of the domain class field is Date, not Timestamp.

Matthias Hryniszak said...

You can check if you don't have some ugly imports like java.sql.* in the source. Other possibility would be to see if the SQL server you are using is not weird this way. Check it out with mysql or hsqlfb to be sure.

k6b said...

I am having the same problem. I have a property of type Date. The rest-api-plugin serializes as string on GET ... but if you try to pass the same value back in via PUT or POST it says the value is not a valid Date. (using Grails 1.3.7)

I tried changing the type to java.sql.Timestamp to understand behavior and get "Failed to convert property value of type java.lang.String to required type java.sql.Timestamp".

Not sure what else to try. Does the rest-api plugin not support fields of Date type?

Matthias Hryniszak said...

I'll check that behavior and will get back to you. At first it sounds like something very strange since the default usage is with RESTful JSON client from Ext JS.

k6b said...

FWIW - I was able to get Date properties to properly deserialize by creating a CustomDateEditorRegistrar as described here: http://stackoverflow.com/questions/2871977/binding-a-grails-date-from-params-in-a-controller. I used date format "yyyy-MM-dd'T'HH:mm:ss'Z'". Too bad grails doesn't support this format out of the box.

I am having another problem now when trying to save many-to-one and many-many relationships. Message is "IllegalArgumentException occurred calling getter of ChildModel.id"

Matthias Hryniszak said...

@k6b: could you share the code on github? Maybe you could post a gist or pull request to the plugin?

k6b said...

Sure. I have logged the Date issue here: https://github.com/padcom/grails-json-rest-api/issues/1 and will try and post the other issues there later today as well.

I can do a pull request but want to fix the many-to-many save issue first. There does seem to be a fairly big bug in the update logic where the else is missing a save(flush:true) like the create has.

mistaecko said...

I am sorry I didn't report back here in August. Of course I came up with the same solution as k6b and registered a custom PropertyEditor.
I also ran into a similar problem with null values not being mapped properly. Solution was a PropertyEditor extending StringMultipartFileEditor with setValue overriden:

public void setValue(Object value) {
if (JSONObject.NULL.getClass().isInstance(value)) {
super.setValue(null);
} else {
super.setValue(value);
}
}

k6b said...

@mistaecko that looks like a nice change. Any chance you could add a pull request for the change on github?