Grails render encodeAsJSON GORM with ObjectId (mongodb)
Here is a Model
import org.bson.types.ObjectId
class Foo{
ObjectId id
String name
}
And here an action
def action = {
render(status:200, contentType:"application/json") {
['foo' : Foo.get(params.id)]
}
}
The action will return something like this
{"foo":{"class":"Foo","id":{"class":"org.bson.types.ObjectId","inc":340737392,"machine":-2019394572,"new":false,"time":1299107672000},"name":"fooName"]}
My question is, how can I send in the json the toString of the ObjectId, I don't want this
"id":{"class":"org.bson.types.ObjectId","inc":340737392,"machine":-2019394572,"new":false,"time":1299107672000}
I want something more like
"id":18893828183
I know I can select the parameters I want like:
def foo = Foo.get(params.id)
['foo' : 'Foo' :[id:foo.id.toString(), name:foo.name]]
But I don't want to declare always what I want to return as json, I want to return all the object, Foo.get(params.id).encodeAsJSON()...
Is there a way to override encodeAsJSON()
I already tried to add this
class Foo{
....
static transients : ['idStr']
def getIdStr(){
return this.id.toString()
}
....
}
But it's ignored in the encodeAsJSON()
I even tried this
class Foo{
....
def toJSON(){
def obj = this.encodeAsJSON()
def json = new JsonSlurper().parseText(obj);
json.idString = this.id.toString()
return json.toString()
}
...
}
this "works", but no....
because after this
render(status:200, contentType:"application/json") {
['foo' : Foo.get(params.id).toJSON()]
}
the render encode the json, so everything is "escaped"....
So what do you think is the solution, with a builder always defining what I want to return?
Hope, I made my question clear....
I'll start with the builder, hope you can give me another simpler / cleaner solution...
Thanks
edit I just did a method that returns the object as a map so now I do something like this
render(status:200, contentType:"application/json") {
['foo' : getF开发者_StackOverflow中文版ooAsMap(Foo.get(params.id))]
}
Register this objectMarshaller at Bootstarp.groovy and it will work like a charm
import grails.converters.JSON
import org.bson.types.ObjectId
JSON.registerObjectMarshaller(ObjectId) {
return it.toStringMongod()
}
If you're going to be JSON-encoding your domain classes out to the web, I wonder if ObjectId might not be the best choice? The GORM/MongoDB integration allows you to use any type for the id. You could just declare it as a String type (which can be assigned as a toString of an ObjectId if you like to use that for its randomness) and then you don't need to worry about this mess. Any performance/scalability problems from this could be analysed/dealt with later, but I wouldn't expect there to be any unless it's a very large app.
Use GStrings in your map and you will get a numeric value for your ObjectId. E.g.
render ["foo":"$foo.id"] as JSON
You can do this too:
def domainObj = YourDomainClass.get(params.id)
Map props = [:]
def domain = new DefaultGrailsDomainClass(YourDomainClass.class)
domain.properties.each{
props[it.name] = domainObj[it.name]
}
props["id"] = domainObj.id.toString()
render props as JSON
Or better yet, make it reusable. Put this closure someplace handy:
def mongoObjectResponse = {dobj ->
Map props = [:]
def domain = new DefaultGrailsDomainClass(YourDomainClass.class)
domain.properties.each{
props[it.name] = dobj[it.name]
}
props["id"] = dobj.id.toString()
// I like to leave room in my responses for messages and such
message = ""
obj = props
}
Then call like this from your controller:
return render(contentType: "text/json") {
mongoObjectResponse.delegate = delegate
mongoObjectResponse(domainObj)
}
Just define your domain class as
class Foo {
String id
String name
}
Instead of ObjectId
精彩评论