Search code examples
jsongroovyjsonbuilder

How to Generate an Array of Objects with Nested Siblings with Groovy JsonBuilder


I'm trying to generate a JSON array with multiple nested objects.

Here's what I'd like to generate: (shortened output since I want an array, this just repeats if you run the code):

[
    {
        "User": {
            "Name": "Foo",
            "Email": "[email protected]"
        },
        "Details": {
            "Address": {
                "City": "Anywhere",
                "Country": "USA",
                "State": "ID",
                "ZipCode": "55842"
            },
            "FavoriteColor": "Blue"            
        }
    }
]

Instead I'm generating this:

[
        {
            "User": {
                "Name": "Foo",
                "Email": "[email protected]"
            },
            "Address": {
                "City": "Anywhere",
                "Country": "USA",
                "State": "ID",
                "ZipCode": "55842"
            },
            "Details": [
                {
                    "FavoriteColor": "Blue"
                },
                {
                    "City": "Anywhere",
                    "Country": "USA",
                    "State": "ID",
                    "ZipCode": "55842"
                }
            ]
        }
    ]

Here's my code:

def array = 1..3

def builder = new groovy.json.JsonBuilder()
builder array.collect { itemNumber ->
    [{
        User(
            Name: "Foo" + itemNumber,
            Email: "[email protected]"
        )
        Details(
            Address(
                City: "Anywhere",
                Country: "USA",
                State: "ID",
                ZipCode: "55842"
            ),
            FavoriteColor: "Blue"
        )
    }
    ]
}

println groovy.json.JsonOutput.prettyPrint(builder.toString())

Solution

  • Like mentioned in the comments, in my experience it's better to stay with lists and maps in groovy and only convert to json as a final step. This way you get to use all the groovy goodness for handling maps and lists (collect, findAll, groupBy, etc) to mutate your data and then as a final step generate your json.

    Example code:

    import groovy.json.JsonOutput
    
    def numbers = 1..3
    
    def data = numbers.collect { n -> 
      [
        User: [
          Name: "Foo${n}", 
          Email: "[email protected]"
        ],
        Details: [
          Address: [
            City:     "Anywhere", 
            Country:  "USA", 
            State:    "ID", 
            ZipCode:  "55842"
          ],
          FavoriteColor: "Blue"
        ]
      ]
    }
    
    def json   = JsonOutput.toJson(data)
    def pretty = JsonOutput.prettyPrint(json)
    println "JSON:\n${pretty}"
    

    when run it generates:

    ─➤ groovy solution.groovy
    JSON:
    [
        {
            "User": {
                "Name": "Foo1",
                "Email": "[email protected]"
            },
            "Details": {
                "Address": {
                    "City": "Anywhere",
                    "Country": "USA",
                    "State": "ID",
                    "ZipCode": "55842"
                },
                "FavoriteColor": "Blue"
            }
        },
        {
            "User": {
                "Name": "Foo2",
                "Email": "[email protected]"
            },
            "Details": {
                "Address": {
                    "City": "Anywhere",
                    "Country": "USA",
                    "State": "ID",
                    "ZipCode": "55842"
                },
                "FavoriteColor": "Blue"
            }
        },
        {
            "User": {
                "Name": "Foo3",
                "Email": "[email protected]"
            },
            "Details": {
                "Address": {
                    "City": "Anywhere",
                    "Country": "USA",
                    "State": "ID",
                    "ZipCode": "55842"
                },
                "FavoriteColor": "Blue"
            }
        }
    ]
    

    A note on map keys in groovy, I did not quote mine above because when your keys are valid identifiers (i.e. not something like Favourite-Color) you don't need quotes. If you run into keys that break the above pattern, you can always quote the keys.