开发者

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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜