3

I'm trying to use JsonBuilder with Groovy to dynamically generate JSON. I want to create a JSON block like:

{
    "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]
    }]
}

I've written:

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(builder, "type", myCustomVal1)
        addUrn(builder, "urn", "some:urn:$myCustomVal2")
        "date" {
            epoch 1265662800000
            str "2010-02-08T21:00:00Z"
        }
       "metadata" ({
                ratings ({
                        rating "G"
                        scheme "eirin"
                        addUrn(builder, "_type", "$myCustomVal3")
                })
                creators "Jim", "Bob", "Joe"                    
        })
    }

    return root.toString();
}

But I've run into the following issues:

  1. Whenever I call addUrn, nothing is returned in the string. Am I misunderstanding how to use methods in Groovy?
  2. None of the values are encapsulated in double (or single) quotes in the returned string.
  3. Anytime I use a {, I get a '_getEpisode_closure2_closure2@(insert hex)' in the returned value.

Is there something wrong with my syntax? Or can someone point me to some example/tutorial that uses methods and/or examples beyond simple values (e.g. nested values within arrays).

NOTE: This is a watered down example, but I tried to maintain the complexity around the areas that were giving me issues.

Devin
  • 1,014
  • 1
  • 9
  • 28

1 Answers1

2
  1. You have to use delegate in addUrn method instead of passing the builder on which you are working.

  2. It is because you are doing a toSting() or toPrettyString() on root instead of builder.

  3. Solved if #2 is followed.

Sample:

def builder = new groovy.json.JsonBuilder()
def root = builder {
              name "Devin"
              data {
                 type "Test"
                 note "Dummy"
              }
              addUrn(delegate, "gender", "male")
              addUrn(delegate, "zip", "43230")
           }


def addUrn(parent, type, urnVal) {
    parent."$type" {
        __type "urn"
        "value" urnVal
    }
}

println builder.toPrettyString()

Output:-

{
    "name": "Devin",
    "data": {
        "type": "Test",
        "note": "Dummy"
    },
    "gender": {
        "__type": "urn",
        "value": "male"
    },
    "zip": {
        "__type": "urn",
        "value": "43230"
    }
}
dmahapatro
  • 49,365
  • 7
  • 88
  • 117
  • Yup, the `delegate` did the trick. However, when I do builder.toString() I get a stackOverflowError (ReflectiveOperationException). – Devin Jun 27 '13 at 20:24
  • @Devin What script are you trying with? Are you getting exception from my sample code? – dmahapatro Jun 27 '13 at 20:37
  • @Devin Have a look at [this question](http://stackoverflow.com/questions/5538423/grails-jsonbuilder) if you are talking about nested objects. – dmahapatro Jun 27 '13 at 20:51
  • By commenting out my nested types (in this case, the 'metadata'), it worked wonderfully. I'll take a look at that link and see what I can learn. Thanks! – Devin Jun 27 '13 at 21:35
  • 1
    @Devin Just comment out `addUrn` inside `metadata` everything will work fine. Three things to take care: 1.`delegate` has to be set to the immediate parent. In this case, `delagate` has to be `ratings` when you call addUrn inside ratings. 2. You would not get a json array for `metadata` and `ratings` with the implementation you have now, it will be normal json object. Have to use `.collect` hopefully to get a list to be converted to json array. 3. Finally, have a look at [StreamingJsonBuilder](http://groovy.codehaus.org/gapi/groovy/json/StreamingJsonBuilder.html) to use instead of JsonBuilder. – dmahapatro Jun 27 '13 at 21:45
  • How do you set the value of `delegate` to the immediate parent? – Devin Jun 27 '13 at 21:57
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/32527/discussion-between-devin-and-dmahapatro) – Devin Jun 27 '13 at 22:20