问题
(This is a follow up question to a question asked here)
I'm using Groovy's JsonBuilder to dynamically generate the following JSON:
{
"type": {
"__type": "urn",
"value": "myCustomValue1"
},
"urn": {
"__type": "urn",
"value": "myCustomValue2"
},
"date": {
"epoch": 1265662800000,
"str": "2010-02-08T21:00:00Z"
},
"metadata": [{
"ratings": [{
"rating": "NR",
"scheme": "eirin",
"_type": {
"__type": "urn",
"value": "myCustomValue3"
}
}],
"creators": [Jim, Bob, Joe]
}]
}
Using this code:
def addUrn(parent, type, urnVal) {
parent."$type" {
__type "urn"
"value" urnVal
}
}
String getEpisode(String myCustomVal1, String myCustomVal2, String myCustomVal3) {
def builder = new groovy.json.JsonBuilder()
builder {
addUrn(delegate, "type", myCustomVal1)
addUrn(delegate, "urn", "some:urn:$myCustomVal2")
"date" {
epoch 1265662800000
str "2010-02-08T21:00:00Z"
}
"metadata" ({
ratings ({
rating "G"
scheme "eirin"
addUrn(delegate, "_type", "$myCustomVal3")
})
creators "Jim", "Bob", "Joe"
})
}
return root.toString();
}
The code throws a StackOverflowError
because of the third call to addUrn
(under the nested ratings
element. If I comment that line out, it works perfectly (other than the fact that I'm missing a necessary chunk of info).
- Why is this happening?
- How to I set the delegate to the immediate parent, e.g.
ratings
?
I've tried using the metaClass to no avail.
回答1:
This is pretty ugly (LOL) , but will give you the expected result:
def addUrn(parent, type, urnVal) {
parent."$type" {
__type "urn"
"value" urnVal
}
}
String getEpisode(String myCustomVal1, String myCustomVal2, String myCustomVal3) {
def builder = new groovy.json.JsonBuilder()
def root = builder {
addUrn(delegate, "type", myCustomVal1)
addUrn(delegate, "urn", "some:urn:$myCustomVal2")
"date" {
epoch 1265662800000
str "2010-02-08T21:00:00Z"
}
"metadata" ([{([
"ratings" ([{
rating "G"
scheme "eirin"
this.addUrn(delegate, "_type", "$myCustomVal3")
}]),
creators ("Jim", "Bob", "Joe")
])}])
}
println builder.toPrettyString()
}
Note:-
- In the previous question, I was incorrect in saying that delegate has
to refer to immediate parent. Actually it does refer to immediate
parent. Instead, we have to refer to the script (which has the
addUrn
method) while calling the method, hence use ofthis
when callingaddUrn
inside ratings. Alternatively you can ship "ratings" to a method similar toaddUrn
. - The use and sequence of parenthesis, chain brace and square brace is important what you see after "metadata". Making understand that will be cumbersome here. But only thing to keep an eye on is to stick to the basics of using method calls, declaring lists and use of closures. Try to indent each brace per line, you would be able to grab the underlying magic. :)
- The reason for StackOverFlow error was that the method
getEpisode
was unable to reach the methodaddUrn
which is owned by the script.
Test it directly in Groovy Web Console
来源:https://stackoverflow.com/questions/17355304/setting-delegate-value-with-groovy-jsonbuilder