March 13, 2016

Groovy by example: JSON handling (part 1 of 2)



You’ll find a lot of simple examples of dealing with JSON in Groovy on the web. In this article, however, I’ll try to provide a use-case driven collection of recipes, showing you when to apply which specific technique to solve your JSON-related problem.

This article covers:
Throughout this article, I will use a simple example domain model which serves as the structure for our JSON data. Here are the individual Groovy classes (AST transformations omitted):
class Customer {
    String name
    Address address // to-one-relationship
    List<Purchase> purchases // to-many-relationship (generic)
    Map<DiscountType, Integer> discounts // map (generic, with enum keys)
}

class Address {
    String street
    String city
    String country
    
    public String getCity() {
        return "City of $city"
    }
}

class Purchase {
    int price
    Date date
}

enum DiscountType {
    FIDELITY,
    EMPLOYEE,
    EU,
}

Parsing / reading JSON

In the most simple case, you just want to read an excerpt (maybe even just a single property) of a JSON String.

Here’s a example JSON String:
[
    {
        "name": "Max",
        "address": {
            "street": "First Street",
            "city": "Los Angeles",
            "country": "US"
        },
        "purchases": [
            {
                "date": "2016-03-13 00:00:00",
                "price": 100
            },
            {
                "date": "2016-03-13 00:00:00",
                "price": 200
            },
            {
                "date": "2016-03-13 00:00:00",
                "price": 300
            }
        ]
    },
    {
        "name": "Sarah",
        "address": {
            "street": "Second Street",
            "city": "San Francisco",
            "country": "US"
        },
        "purchases": [
            {
                "date": "2016-03-12 00:00:00",
                "price": 200
            }
        ]
    }
]
You can parse this String easily using Groovy’s JsonSlurper which supports Groovy’s property access syntax (GPath notation), resulting in highly readable code.

Get the root element (here it’s a list):
def root = new JsonSlurper().parseText(TEST_CUSTOMERS_JSON)
And then access child nodes:
root[0].name // "Max"
Because node collections are iterable, you can also invoke Groovy’s iteration methods on them:
root.collect {customer -> customer.purchases.findAll {it.price > 200}}.flatten()*.price // [300]
Note that this method of accessing a JSON structure is designed for use in dynamically compiled code only. Otherwise, above code segments would get seriously bloated as you would have to cast to Collections or Maps in order to make the compiler happy.

Writing JSON

Groovy also comes with built-in tools to write dynamically or statically defined JSON using the elegant Groovy builder syntax.

Create a JsonBuilder:
def builder = new JsonBuilder()
And then build the structure:
builder.call(
    [ 
        builder (
            name: "Max",
            address: address(builder, "First Street", "Los Angeles"),
            purchases: (1..3).collect { num ->
                builder (
                    date: "2016-03-13 00:00:00",
                    price: num * 100,
                )
            }
        ),
        builder (
            name: "Sarah",
            address: address(builder, "Second Street", "San Francisco"),
            purchases: [
                builder (
                    date: "2016-03-12 00:00:00",
                    price: 200,
                )
            ]
        )
    ]
)
whereby address(…) is
private static address(def builder, String street, String city) {
    return builder (
        street: street,
        city: city,
        country: "US"
    )
}
There are a few advanced techniques you can use to make your builder more powerful:
  • Use structural programming facilities to build a structure dynamically (in the example, we build Max’s purchases dynamically from an int range).
  • Use helper methods as “templates” to keep your code DRY compliant (in the example, this is implemented by the address(…) method).
(I have explained a bunch of these techniques in another blog post which deals with Groovy builders in general.)

Finally, pretty-print the output JSON String:
JsonOutput.prettyPrint(builder.toString())
The example will result in the JSON output depicted in the previous section.

Transforming / manipulating JSON

In this case, the input as well as the output is JSON. There’s no need for an intermediate Java object representation of the model.

This really is most easily achieved by subsequently parsing JSON, manipulating the returned structure, and then writing it as JSON using the techniques discussed above.

You can use any Groovy facilities to do the model restructuring.

This code example will change the “US” country code to the “USA” code, and add additional currency information to a customer:
def root = new JsonSlurper().parseText(TEST_CUSTOMERS_JSON)

root.findAll { customer -> customer.address.country == "US"}.each {
    it.address.country = "USA"
    it.info = [currency: "USD"]
}
In the final step, we initialize the JsonBuilder with the manipulated JSON node structure and simply print it again.
def builder = new JsonBuilder(root)
JsonOutput.prettyPrint(builder.toString())


Pages: 1 2