1

I have a similar problem to this: Grails get child domain objects

I'll just paste domain class code from the link for the post to be mor readable:

class Parent{
   String name
   static hasMany = [childs:Child] 
   static constraints = {
   }
}

class Child{
   String name
   static belongsTo = [parent:Parent]
   static constraints={}
}

I have created custom marshaller for Parrent object that produces something like below. How do I receive and save a complex JSON object like that one ? (I want to receive identical objects like the one that marshaller generated for me)

[{"class":"project.Parent","id":1,"name":"name1",
  "childs":[{"class":"Child","id":1,"name":"childname1"},
            {"class":"Review","id":2,"name":"childname2"}
           ]
}]

besides JSON if I had, say, all the parameters like "name" and such, the default saving code in my app is:

def parrent = new Parrent("parr_name") 
parrent.save()
def child = new Child("child_name", parrent)
child.save()  

Do I have to send JSON object separately? or could I just receive complex json and drag out map of args? Does the marshaller implemented for display JSON in such manner is capable of receiving one in similar format? I am using grails v2.3.3

Community
  • 1
  • 1
sliwczy
  • 11
  • 5

1 Answers1

2

Grails 2.3.* ships with a re-defined data binding framework where you can bind a JSON payload (from a POST request in most cases) directly to the domain classes.

It works the same smart way you have tailored a marshaller for the response JSON. The way CommandObjects were used in earlier version of Grails it can be used likewise. Taking your own example:

class Parent {
    String name
    static hasMany = [children:Child]
}

class Child {
    String name
    static belongsTo = [parent:Parent]
}

//In Controller
class ParentController {

    //Directly binding the payload JSON to Parent domain class
    //Caveat here is if the corresponding Parent domain matching the id in the
    //payload is not found then "parent" parameter 
    //in the below action will be null 
    def save(Parent parent) {
        println "Parent Data $parent"
        println "Child Data $parent.children"

        render "Parent Data $parent and child data $parent.children"

        //or Do other stuff
    }
}

//Assuming you have parent and child already present
class BootStrap {
    def init = { servletContext ->
        def parent = new Parent(name: "name1")

        def child1 = new Child(name: "childname1")
        def child2 = new Child(name: "childname2")

        parent.addToChildren(child1)
        parent.addToChildren(child2)

        parent.save(flush: true, failOnError: true)
    }
}

//and payload as
POST http://localhost:8080/YourApp/parent/save
Content-Type: application/json

{"class":"project.Parent","id":1,"name":"name1",
  "childs":[{"class":"Child","id":1,"name":"childname1"},
            {"class":"Child","id":2,"name":"childname2"}
           ]
}

//curl command like
curl -X POST 
     -H "Content-Type: application/json" 
     -d '{"class":"project.Parent","id":1,"name":"name1",
          "childs":[{"class":"Child","id":1,"name":"childname1"},
                    {"class":"Child","id":2,"name":"childname2"}
                   ]
         }' 
      http://localhost:8080/YourApp/parent/save

You should be able to bind the JSON payload to the Parent domain (with children) directly. Same would be applicable if you are using url parameters instead of JSON.

dmahapatro
  • 49,365
  • 7
  • 88
  • 117