rajugaadu
rajugaadu

Reputation: 714

Grails: Easy and efficient way to parse JSON from a Request

Please pardon me if this is a repeat question. I have been through some of the questions/answers with a similar requirement but somehow got a bit overwhelmed and confused at the same time. My requirement is:

Here is the JSON that my grails controller will be receiving:

{
    "loginName":"user1",
    "timesheetList":
    [
        {
            "periodBegin":"2014/10/12",
            "periodEnd":"2014/10/18",
            "timesheetRows":[
                {
                    "task":"Cleaning",
                    "description":"cleaning description",
                    "paycode":"payCode1"
                },
                {
                    "task":"painting",
                    "activityDescription":"painting description",
                    "paycode":"payCode2"
                }
            ]
        }
    ],
    "overallStatus":"SUCCESS"
}

Questions:

  1. How can I retrieve the whole JSON string from the request? Does request.JSON be fine here? If so, will request.JSON.timesheetJSON yield me the actual JSON that I want as a JSONObject?

  2. What is the best way to parse through the JSON object that I got from the request? Is it grails.converters.JSON? Or is there any other easy way of parsing through? Like some API which will return the JSON as a collection of objects by automatically taking care of parsing. Or is programatically parsing through the JSON object the only way?

Like I said, please pardon me if the question is sounding vague. Any good references JSON parsing with grails might also be helpful here.

Edit: There's a change in the way I get the JSON string now. I get the JSON string as a request paramter.

String saveJSON // This holds the above JSON string.

def jsonObject = grails.converters.JSON.parse(saveJSON) // No problem here. Returns a JSONObject. I checked the class type.
def jsonArray = jsonArray.timesheetList // No problem here. Returns a JSONArray. I checked the class type.
println "*** Size of jsonArray1: " + jsonArray1.size() // Returns size 1. It seemed fine as the above JSON string had only one timesheet in timesheetList

def object1 = jsonArray[1] // This throws the JSONException, JSONArray[1] not found. I tried jsonArray.getJSONObject(1) and that throws the same exception.

Basically, I am looking to seamlessly iterate through the JSON string now.

Upvotes: 4

Views: 7547

Answers (2)

Oleg Baskakov
Oleg Baskakov

Reputation: 41

I see your example contains errors, which lead you to implement more complex JSON parsing solutions. I rewrite your sample to the working version. (At least now for Grails 3.x)

String saveJSON // This holds the above JSON string.

def jsonObject = grails.converters.JSON.parse(saveJSON) 
println jsonObject.timesheetList // output timesheetList structure

println jsonObject.timesheetList[0].timesheetRows[1] // output second element of timesheetRows array: [paycode:payCode2, task:painting, activityDescription:painting description]

Upvotes: 0

papacito
papacito

Reputation: 368

I have wrote some code that explains how this can be done, that you can see below, but to be clear, first the answers to your questions:

  1. Your JSON String as you wrote above will be the contents of your POST payload to the rest controller. Grails will use its data binding mechanism to bind the incomming data to a Command object that your should prepare. It has to have fields corresponding to the parameters in your JSON String (see below). After you bind your command object to your actual domain object, you can get all the data you want, by simply operating on fields and lists

  2. The way to parse thru the JSON object is shown in my example below. The incomming request is esentially a nested map, with can be simply accessed with a dot

Now some code that illustrates how to do it. In your controller create a method that accepts "YourCommand" object as input parameter:

def yourRestServiceMethod (YourCommand comm){
    YourClass yourClass = new YourClass()
    comm.bindTo(yourClass)

    // do something with yourClass
    // println yourClass.timeSheetList
}

The command looks like this:

class YourCommand {
    String loginName
    List<Map> timesheetList = []
    String overallStatus

    void bindTo(YourClass yourClass){
        yourClass.loginName=loginName
        yourClass.overallStatus=overallStatus
        timesheetList.each { sheet ->
            TimeSheet timeSheet = new TimeSheet()
            timeSheet.periodBegin = sheet.periodBegin
            timeSheet.periodEnd = sheet.periodEnd
            sheet.timesheetRows.each { row ->
                TimeSheetRow timeSheetRow = new TimeSheetRow()
                timeSheetRow.task = row.task
                timeSheetRow.description = row.description
                timeSheetRow.paycode = row.paycode
                timeSheet.timesheetRows.add(timeSheetRow)
            }

            yourClass.timeSheetList.add(timeSheet)
        }
    }
}

Its "bindTo" method is the key piece of logic that understands how to get parameters from the incomming request and map it to a regular object. That object is of type "YourClass" and it looks like this:

class YourClass {
    String loginName
    Collection<TimeSheet> timeSheetList = []
    String overallStatus
}

all other classes that are part of that class:

class TimeSheet {
    String periodBegin
    String periodEnd
    Collection<TimeSheetRow> timesheetRows = []
}

and the last one:

class TimeSheetRow {
    String task
    String description
    String paycode
}

Hope this example is clear enough for you and answers your question

Edit: Extending the answer according to the new requirements

Looking at your new code, I see that you probably did some typos when writting that post

def jsonArray = jsonArray.timesheetList

should be:

def jsonArray = jsonObject.timesheetList

but you obviously have it properly in your code since otherwise it would not work, then the same with that line with "println":

jsonArray1.size()

shuold be:

jsonArray.size()

and the essential fix:

def object1 = jsonArray[1]

shuold be

def object1 = jsonArray[0]  

your array is of size==1, the indexing starts with 0. // Can it be that easy? ;)

Then "object1" is again a JSONObject, so you can access the fields with a "." or as a map, for example like this: object1.get('periodEnd')

Upvotes: 5

Related Questions