Kyle Banks

Customizing JSON Output in Grails with JSON Object Marshaller

Written by @kylewbanks on Mar 6, 2013.

One of my favourite features of Grails is the ability to render just about any object as JSON. This makes the creation of REST API calls a breeze, but one problem with the default implementation is that it renders the entire object as JSON. This isn't always an issue, but if for example you are rendering a User object, you (hopefully) don't want to output the user's password. You may also wish to limit the size of the JSON, by removing output that is simply not necessary.

Lucky for us, Grails allows deep customization in how your JSON is written.

Let's look at a simple domain object, Review which describes just that. A user reviewing another user.

class Review {
    static belongsTo = [reviewer: User, reviewedUser: User]

    String reviewContent
    Integer reviewRating
    Date dateCreated
}

So what do we want the JSON to look like? Well, I'd like to see the id of the Review, the content and rating, as well as the date created. In addition, our API clients may want to show the name of the reviewer and reviewed user. If they want to show more information about either of these two users, they will need the id of each in order to retrieve more, so we will return that as well.

The process is very simple. We register our Review class with the JSON object marshaller. When we do this, we construct a Map containing all of the data we want to return. (I normally register all of the neccessary classes in BootStrap.groovy but you can basically put it anywhere, so long as it's registered before you call render as JSON.)

//Register Review domain for JSON rendering
JSON.registerObjectMarshaller(Review) {
    def output = [:]
    output['id'] = it.id
    output['reviewContent'] = it.reviewContent
    output['reviewRating'] = it.reviewRating
    output['dateCreated'] = dateFormatter.format(it.dateCreated)
    output['reviewer'] = ["id": it.reviewer.id, "name": it.reviewer.getFullName()]
    output['reviewedUser'] = ["id": it.reviewedUser.id, "name": it.reviewedUser.getFullName()]

    return output;
}

Within the JSON.registerObjectMarshaller(Object o) { } closure, it refers to the instance of the object whose class is being registered. So, in the previous example, it is an instance of Review.

Now that the Review class has been registered, we are all setup to output any instance of Review as JSON.

//A single review
Review review = Review.findById(id);
render review as JSON

//A list of reviews
def reviews = Review.findAllByReviewer(reviewingUser)
render reviews as JSON

//An object containing reviews
User user = User.findById(id); //User hasMany reviews
render user as JSON

As you can see above, any other objects that you render as JSON which contain Review objects will also have their reviews rendered as we designed.

The JSON class in Grails is extremely powerful out of the box, but with this added customization it becomes the API developer's best friend.

Let me know if this post was helpful on Twitter @kylewbanks or down below!