Saturday, May 21, 2011

Groovy 1.8 Introduces Groovy to JSON

There are many things to like about JavaScript Object Notation (JSON) as a "a lightweight data-interchange format." In particular, JSON is often compared favorably against XML because of the similar uses of each format. Although JSON is as "a subset of the object literal notation of JavaScript" and is particularly easy to use in JavaScript because of this, numerous other languages have adopted support for JSON either through frameworks and libraries or even through built-in language support. Douglas Crockford has stated, "JSON is a natural representation of data for the C family of programming languages." In this post, I look at using JSON in Groovy 1.8 after looking at Java's support for JSON and after providing a brief overview of JSON.


Java and JSON

Many of us have wanted to see JSON support built into Java as a standard part of the language. There has even been talk of a JSR for JSON in Java. However, as of this writing, JSON support in Java applications must be achieved with separate libraries such as Douglas Crockford's reference implementation, the Jackson Java JSON-processor (reported to be used by the REST Java frameworks Jersey, RESTEasy, and Enunciate [JSON is rapidly replacing XML in many Ajax-powered applications] and by the JVM language Clojure), json-lib (includes Groovy integration), JAX-WS Commons, and several others (including some reviewed in A Review of 5 Java JSON Libraries). Although Java still lacks built-in JSON support, Groovy no longer lacks native JSON support as of Groovy 1.8.


JSON Overview

Because there are numerous good introductions to JSON, I attempt to keep my overview of JSON in this post to the bare minimum to support my examples of using JSON with Groovy 1.8's native JSON capabilities. Good introductory JSON references include Introduction to JSON (JavaScript Object Notation) [PowerPoint slides on slideshare], JSON: The Fat-Free Alternative To XML [also PowerPoint slides on slideshare], and Introduction to JavaScript Object Notation (JSON) [PDF].

Perhaps the best place to start familiarizing oneself with JSON is the main Introducing JSON page. This single web page provides an overview of JSON in fewer than eight printed pages and manages in those few pages to introduce JSON, describe some of its benefits and features, explain how JSON describes common data structures, list languages with built-in or library support for JSON [covering numerous languages from ASP through Visual FoxPro and listing 19 libraries for Java's JSON support!], and concludes with links to numerous other references. The very ability to fit all of this into fewer than eight printed pages reinforces JSON's greatest benefit: simplicity.

At its essence, JSON is about formatting data in name/value pairs. There are advantages to this approach. First, we see name/pairs in a wide variety of software development areas. This familiarity makes it easier to learn and use JSON. For example, Java developers are very familiar with the name/value pair format used in Java properties. The map/associative array data structures leverage name/value pairs as well. Many languages, including Groovy, support named method parameters which provide another example of the prevalence of name/value pairs.

A second advantage of JSON's name/value formatting is that it is highly readable and easily editable even for those not familiar with JSON. Nesting of JSON name/value pairs allows for more complex and even hierarchical representations to be easily modeled. An example is probably the easiest way to see this and the JSON Example page provides multiple nice comparisons of JSON to XML. I'll show my own example of data in JSON format a little later, but I'm going to let Groovy 1.8 generate the example JSON for me.


Groovier JSON

Groovy 1.8 provides native support for JSON. The next Groovy code listing takes advantage of Groovy's JsonBuilder support.

buildJsonState.groovy
#!/usr/bin/env groovy

/**
 * buildJsonState.groovy
 *
 * Simple Groovy script demonstrating Groovy 1.8 support for Json generation.
 * Requires Groovy 1.8.
 */

import groovy.json.JsonBuilder
import groovy.json.JsonOutput

def json = new JsonBuilder()

json.state
{
   name "Colorado"
   statehood 1876
   capital "Denver"
   majorCities "Denver", "Colorado Springs", "Fort Collins"
}

println json

json.state 
{
   name "Utah"
   statehood 1896
   capital "Salt Lake City"
   majorCities "Salt Lake City", "Ogden", "Provo", "Logan"
}

println json

As the example code above indicates, Groovy's JsonBuilder is intentionally similar to the other Groovy builder such as MarkupBuilder. When the above script is run, the output appears as shown in the following screen snapshot.


There is nothing wrong with the above, but many JSON examples use white space (new lines and indenting) to improve the readability of the JSON. Groovy makes this easy with the JsonOutput.prettyPrint(String) method. This method accepts a String and returns a JSON-ified version of that String. This method is applied to the above code listing and the adapted version is shown in the next code listing.

#!/usr/bin/env groovy

/**
 * buildJsonState.groovy (adapted for pretty print)
 *
 * Simple Groovy script demonstrating Groovy 1.8 support for Json generation and
 * for providing the JSON output in "pretty print" format (with white space).
 * Requires Groovy 1.8.
 */

import groovy.json.JsonBuilder
import groovy.json.JsonOutput

def json = new JsonBuilder()

json.state
{
   name "Colorado"
   statehood 1876
   capital "Denver"
   majorCities "Denver", "Colorado Springs", "Fort Collins"
}

println JsonOutput.prettyPrint(json.toString())

json.state 
{
   name "Utah"
   statehood 1896
   capital "Salt Lake City"
   majorCities "Salt Lake City", "Ogden", "Provo", "Logan"
}

println JsonOutput.prettyPrint(json.toString())

The output from running the script above is the same in terms of substance returned, but the white space additions make the change appear dramatic and make the output more readable. The next screen snapshot demonstrates this.


The examples above represent valid JSON with name/value pairs. The list of major cities was included to show how JSON represents multiple items in the "value" portion.

The just-mentioned JsonOutput class does more than support pretty printing a JSON string. It also includes methods for producing JSON Strings appropriate for a provided Java (or Groovy) data structure. These methods are all called toJson and are overloaded based on the provided parameter. The following structures and data types are currently supported: Boolean, Number, String, Closure, Object, and Map.

The JsonOutput.prettyPrint(String) method was useful for providing the JSON in a more intuitive form. However, I did not really need to use the JsonOutput class at all because JsonBuilder (which I was already using) has its own toPrettyString() method that can be invoked rather than explicitly or implicitly calling its toString() as I did in the examples above. The next code example shows this. Because JsonOutput is no longer needed, I was able to remove its import statement. I also decided to add a few cities as "major cities" while changing the code anyway.

buildJsonState.groovy with Pretty Print via JsonBuilder
#!/usr/bin/env groovy

/**
 * buildJsonState.groovy (adapted for pretty print)
 *
 * Simple Groovy script demonstrating Groovy 1.8 support for Json generation and
 * for providing the JSON output in "pretty print" format (with white space).
 * Requires Groovy 1.8.
 */

import groovy.json.JsonBuilder

def json = new JsonBuilder()

json.state
{
   name "Colorado"
   statehood 1876
   capital "Denver"
   majorCities "Denver", "Colorado Springs", "Fort Collins", "Boulder", "Grand Junction"
}

println json.toPrettyString()

json.state 
{
   name "Utah"
   statehood 1896
   capital "Salt Lake City"
   majorCities "Salt Lake City", "Ogden", "Provo", "Logan", "St. George"
}

println json.toPrettyString()

The output from the above looks the same as before, but with the extra cities.


I find that Groovy's slurping of XML is more important to me than Groovy's writing of XML. It could turn out that the same will be true for Groovy's JSON support and the reading of JSON may be the most important feature. JsonSlurper works similarly to XmlSlurper as shown in the next code listing which slurps the JSON written by the last example (I piped that examples output to the file states.js and removed all but the part describing Colorado).

states.js
{
    "state": {
        "name": "Colorado",
        "statehood": 1876,
        "capital": "Denver",
        "majorCities": [
            "Denver",
            "Colorado Springs",
            "Fort Collins",
            "Boulder",
            "Grand Junction"
        ]
    }
}

The listing above shows the relevant portion of the output of the above scripts. This output is the input for the next code listing that demonstrates slurping JSON with Groovy.

#!/usr/bin/env groovy

/**
 * readStatesJson.groovy
 *
 * Simple example of slurping JSON in Groovy 1.8.
 */

def jsonPayload = new File("states.js").text

import groovy.json.JsonSlurper
def slurper = new JsonSlurper()
def states = slurper.parseText(jsonPayload)

states.state.each
{
   println it
}

The simple example leads to this output:



Groovy and JSON: Simple Goes Well with Simpler

It is not surprising that Groovy feels like a great fit for JSON. Although JSON can easily be used independent of programming language, the simplicity of Groovy combined with the simplicity of JSON as a data format makes the combination of the two powerful, interesting, and compelling. In The Rise of JSON, Karsten Januszewski states that he believes the primary explanation for the "quick and triumphant" rise of JSON "has to do with programming." He specifically compares how easy it is to use JSON in JavaScript as compared to using XML in JavaScript. For Groovy, both are easy to handle thanks to Groovy's excellent XML and JSON support. I believe there are situations where each format shines over the other and Groovy allows me to easily apply the right data format for the job each time.

4 comments:

Martijn Verburg said...

That's awesome stuff! I had covered the XML builder work in my chapter on Groovy, but I'm tempted to go back and update it to show this JSON case as well. Would you be OK with me citing this blog post in the book?

@DustinMarx said...

Martijn,

It would be an honor to have my blog cited in your book. I have only had time to skim the contents of its MEAP updates so far, but have liked what I have seen.

Dustin

Martijn Verburg said...

Consider it done, I'll let you know when it's referenced. Will be a little while, my book TODO list is somewhat overwhelming :)

@DustinMarx said...

Groovy 1.8.0 - Meet JsonBuilder provides additional details regarding Groovy 1.8's JSON support.