Grails JSON数组

Grails JSON数组

问题描述:

我将Foo对象的列表转换为JSON字符串。我需要将JSON字符串解析回Foos列表。然而在下面的例子中,解析给了我一个JSONObjects而不是Foos的列表。Grails JSON数组

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 

我怎样才能解析成FOOS呢? 在此先感谢。

我查看了JSON的API文档,似乎没有任何方法可以将JSON字符串解析为特定类型的对象。

所以你只需要编写自己的代码到每个JSONObject转换为Foo。像这样的东西应该工作:

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")) 
} 

一个更普遍的解决办法是增加一个新的静态parse方法,如下面的JSON metaClass上,试图将JSON字符串解析到一个特定的对象的列表类型:

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'] } 

你可以在groovy控制台中试试上面的代码。一些警告

  • 我只进行非常有限的测试在上面的代码
  • 有在最近2个JSON类Grails的释放,我假设你正在使用的不是过时的一个
+0

是否有可能将每个jsonObj directoy的属性注入foo的每个新实例的foo.properties字段中? – Armand 2010-04-20 13:40:08

+0

@Ali G - 不,我认为'.properties'只能写Grails域对象。对于常规的Groovy对象,我认为'.properties'是只读的。 – 2010-04-20 15:15:51

+0

谢谢唐。通用的方法是非常好的。 – armandino 2010-04-20 15:47:38

如果你是在一个Grails控制器这样做,和富的确是一个域对象,不要忘记,武装你的JSON地图,你也可以这样做:

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

甚至更​​好 Foo foo = new Foo(parsedList [0]) – gabe 2011-01-13 19:40:05

我已经采取了此代码并将其扩展为嵌套结构。它依赖于JSON中存在的'class'属性。如果现在在Grails中有更好的方法,请告诉我。

 // 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

+1我很惊讶没有更好的方法! – Armand 2013-02-13 14:09:55

由于Grails的2.5,这是可能的:

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

输出:

test 

我不确定当它成为一种选择。