Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Grails JSON array

I'm converting a list of Foo objects to a JSON string. I need to parse the JSON string back into a list of Foos. However in the following example, parsing gives me a list of JSONObjects instead of Foos.

Example

List list = [new Foo("first"), new Foo("second")]
def jsonString = (list as JSON).toString()

List parsedList = JSON.parse(jsonString) as List
println parsedList[0].getClass() // org.codehaus.groovy.grails.web.json.JSONObject

How can I parse it into Foos instead? Thanks in advance.

like image 608
armandino Avatar asked Apr 20 '10 00:04

armandino


1 Answers

I had a look at the API docs for JSON and there doesn't appear to be any way to parse to a JSON string to a specific type of object.

So you'll just have to write the code yourself to convert each JSONObject to a Foo. Something like this should work:

import grails.converters.JSON
import org.codehaus.groovy.grails.web.json.*

class Foo {
  def name

  Foo(name) {
    this.name = name
  }

  String toString() {
    name
  }
}


List list = [new Foo("first"), new Foo("second")]
def jsonString = (list as JSON).toString()

List parsedList = JSON.parse(jsonString)

// Convert from a list of JSONObject to a list of Foo
def foos = parsedList.collect {JSONObject jsonObject ->
    new Foo(name: jsonObject.get("name"))
}

A more general solution would be to add a new static parse method such as the following to the JSON metaClass, that tries to parse the JSON string to a List of objects of a particular type:

import grails.converters.JSON
import org.codehaus.groovy.grails.web.json.*

class Foo {
  def name

  Foo(name) {
    this.name = name
  }

  String toString() {
    name
  }
}

List list = [new Foo("first"), new Foo("second")]
def jsonString = (list as JSON).toString()


List parsedList = JSON.parse(jsonString)

// Define the new method
JSON.metaClass.static.parse = {String json, Class clazz ->

    List jsonObjs = JSON.parse(json)

    jsonObjs.collect {JSONObject jsonObj ->

        // If the user hasn't provided a targetClass read the 'class' proprerty in the JSON to figure out which type to convert to
        def targetClass = clazz ?: jsonObj.get('class') as Class
        def targetInstance = targetClass.newInstance()        

        // Set the properties of targetInstance
        jsonObj.entrySet().each {entry ->

            if (entry.key != "class") {
                targetInstance."$entry.key" = entry.value
            }
        }
        targetInstance
    }

}

// Try the new parse method
List<Foo> foos = JSON.parse(jsonString, Foo)

// Confirm it worked
assert foos.every {Foo foo -> foo.class == Foo && foo.name in ['first', 'second'] }

You can try out the code above in the groovy console. A few warnings

  • I have only performed very limited testing on the code above
  • There are two JSON classes in the latest Grails release, I'm assuming you're using the one that is not deprecated
like image 112
Dónal Avatar answered Sep 26 '22 03:09

Dónal