Grails JSON array

后端 未结 4 2172
遇见更好的自我
遇见更好的自我 2021-02-08 03:18

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 JS

相关标签:
4条回答
  • 2021-02-08 03:36

    As of Grails 2.5, this is possible:

    Period test = new Period()
    test.periodText = 'test'
    String j = test as JSON
    def p = JSON.parse(j)
    test = p.asType(Period)
    println(test.periodText)
    

    Output:

    test
    

    I am unsure of when it became an option.

    0 讨论(0)
  • 2021-02-08 03:42

    If you are doing this in a Grails controller, and Foo IS indeed a domain object, don't forget that armed with your JSON map, you can also do:

    List list = [new Foo("first"), new Foo("second")]
    def jsonString = (list as JSON).toString()
    
    List parsedList = JSON.parse(jsonString) as List
    Foo foo = new Foo()
    bindData(foo, parsedList[0]);
    
    0 讨论(0)
  • 2021-02-08 03:44

    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
    0 讨论(0)
  • 2021-02-08 03:45

    I've taken this code and extended it to work with nested structures. It relies on a 'class' attribute existing in the JSON. If there's a better way by now in Grails please let me know.

         // The default JSON parser just creates generic JSON objects.  If there are nested
    
        // JSON arrays they are not converted to theirs types but are left as JSON objects
        // This converts nested JSON structures into their types.
        // IT RELIES ON A PROPERTY 'class' that must exist in the JSON tags
        JSON.metaClass.static.parseJSONToTyped = {def jsonObjects ->
    
            def typedObjects = jsonObjects.collect {JSONObject jsonObject ->
                if(!jsonObject.has("class")){
                    throw new Exception("JSON parsing failed due to the 'class' attribute missing: " + jsonObject)
                }
    
                def targetClass = grailsApplication.classLoader.loadClass(jsonObject.get("class"))
                def targetInstance = targetClass.newInstance()
    
                // Set the properties of targetInstance
                jsonObject.entrySet().each {entry ->
                    // If the entry is an array then recurse
                    if(entry.value instanceof org.codehaus.groovy.grails.web.json.JSONArray){
                        def typedSubObjects = parseJSONToTyped(entry.value)
                        targetInstance."$entry.key" = typedSubObjects
                    }
                    else if (entry.key != "class") {
                        targetInstance."$entry.key" = entry.value
                    }
                }
    
                targetInstance
            }
    
            return typedObjects
        }
    
    0 讨论(0)
提交回复
热议问题