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的释放,我假设你正在使用的不是过时的一个
如果你是在一个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]);
甚至更好 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
}
+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
我不确定当它成为一种选择。
是否有可能将每个jsonObj directoy的属性注入foo的每个新实例的foo.properties字段中? – Armand 2010-04-20 13:40:08
@Ali G - 不,我认为'.properties'只能写Grails域对象。对于常规的Groovy对象,我认为'.properties'是只读的。 – 2010-04-20 15:15:51
谢谢唐。通用的方法是非常好的。 – armandino 2010-04-20 15:47:38