JSON and Java

July 09, 2012 »best-practice

What it is

The creators will know best:

JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate. It is based on a subset of the JavaScript Programming Language. […] JSON is a text format that is completely language independent but uses conventions that are familiar to programmers of the C-family of languages, including C, C++, C#, Java, JavaScript, Perl, Python, and many others. These properties make JSON an ideal data-interchange language.

As the highlighted parts of the quote make it clear, JSON is a format to present data, much like XML.

Why it’s cool

But it has a few advantages over XML:

  • it’s not that verbose
  • it’s (with the right library) easier and faster1 to parse

1 In terms of development time. Not necessarily in terms of CPU-time!

Why it sucks

Of course, JSON does not come free from downsides. The mayor issue with JSON is, that it lags the possibility to define a set of rules which allows a document to be validated. Sure, there is jsonlint.org, but that is really just a syntax checker.

When using XML, you have the basic DTD- and the very powerful Schema-languages to exactly define the hierarchy of elements and their permitted values. This makes validating a language like (X)HTML or RSS easy. Also, it can be used to add auto-completion to an IDE, as it represents a sealed set of rules.

JSON lags something comparable. This leaves you as the user to trust the “hand written” documentation of the format. Aside from that, I have not seen one site to create a corresponding DTD or Schema for their API responses in XML.

There is a distinct difference between XML and JSON: XML is a markup-language, designed to mark something up. JSON is just a data-interchange language, designed to have a very lightweight format for human-readable data-exchange.

Examples

The first point (verbosity) is one of the most famous XML criteria points. To show what this means in real live, let’s have a look at a very easy example: We want to store a simple data-structure which holds information from a contact-book. A contact can have:

  • a name
  • a group
  • one or multiple numbers
  • each number has a group (work, private, etc)

Here’s an example data-structure in XML:

<contacts>
    <contact>
        <name>Jon Doe</name>
        <group>Family</group>
        <numbers>
            <number type="work">XXX - XXXXXX - XX</number>
            <number type="private">XXX - XXXXXX - XX2</number>
        </numbers>
    </contact>
    <contact>
        <name>Lukas Knuth</name>
        <group>Work</group>
        <numbers>
            <number type="work">XXX - 12345</number>
        </numbers>
    </contact>
</contacts>

And here’s the JSON equivalent:

[
    {
        "name": "Jon Doe",
        "group": "Family",
        "numbers": [
            {
                "type": "work",
                "number": 123431
            },
            {
                "type": "private",
                "number": 751239
            }
        ]
    },
    {
        "name": "Lukas Knuth",
        "group": "Work",
        "numbers": [
            {
                "type": "work",
                "number": 412319
            }
        ]
    }
]

Aside from all the fluff in the JSON version, it’s easier to read and not as clumsy as the XML-version. And this is a fairly small amount of data. It gets interesting with 10 or 20 set’s of data.

Working it

So, now that we have our formatted data-sets, how can we parse them so we can work with the data? I’m not going to cover XML-parsing as there are countless articles out there. I’m just going to name three small ones which I personally liked:

Now, for the JSON part of it. We’re going to look at two particular Java libraries, although there are a dozen of them (See json.org, scroll down for the list). The libraries we’ll cover in this article are “org.json” by Douglas Crockford (who was the first to specify and popularize JSON) and “google-gson” from Google Inc.

These libraries have very different approaches to parsing JSON input. While “google-gson” is almost like ORM for JSON, the org.json-package is a very low-level implementation. We’ll cover both of those, when to use which and why.

google-gson

We’ll start with gson, since it’s easier to explain and requires less effort on the developers site. As I said above, it’s much like ORM. Therefor, we’ll first need to specify, what kind of objects the JSON-string represents. We’ll use the example from above.

In our example, we have an array ([]) of (unnamed) objects ({}). Each of those objects has:

  • the fields ("[fieldname]":[value]) “name”, “group” and “numbers”
  • the last one stores an array/list of objects which all have:
    • the fields “type” and “number”

So, we’ll need a Contact-class which holds the name, group and the list of numbers. Also, we’ll need a Number-class to hold the actual numbers and their types. Here is the complete code, including the capsule-classes and the parsing code:

public class GsonTest {

    private final static String JSON = "The above JSON-string";

    public static void main(String[] args){
        Gson gson = new Gson();
        Contact contacts[] = gson.fromJson(JSON, Contact[].class);
        for (Contact c : contacts)
            System.out.println(c);
    }

    public class Contact {
        private String name, group;
        private Number[] numbers;

        @Override
        public String toString(){
            StringBuilder builder = new StringBuilder();
            builder.append("Contact '"+name+"' from group '"+group+"' has"+
                "the following numbers:\n");
            for (Number n : numbers)
                builder.append(n.toString()+"\n");
            return builder.toString();
        }

    }

    public class Number {
        /** Generally bad idea because of leading 0, but just for
        * showing the different data-types...
        */
        private int number;
        private String type;

        @Override
        public String toString(){
            return type+": "+number;
        }
    }

}

Bäm! That was easy. When taking it for a test-run, we see the expected output:

Contact ‘Jon Doe’ from group ‘Family’ has the following numbers:
work: 123431
private: 751239

Contact ‘Lukas Knuth’ from group ‘Work’ has the following numbers:
work: 412319

That is really as easy as it gets. Going the other way around is as simple as writing:

System.out.println(gson.toJson(contacts));

Neat. “google-gson” also has support for Generic Objects, Collections (in limited form) and excluding specific fields from being serialized/deserialized. Explaining those goes beyond the goal of this article. See the “Gson User Guide” for more information.

org.json

As mentioned above, this is a low-level reference-implementation of JSON. It can be used to parse a JSON-string in a DOM-fashioned way. The following is a best-practice advice on how to use the org.json-package:

public class OrgJsonTest {

    private final static String JSON = "The JSON-string";

    public static void main(String[] agrs) throws JSONException {
        JSONArray contacts = new JSONArray(JSON);
        List<Contact> contact_book = new ArrayList<Contact>(2);
        for (int i = 0; i < contacts.length(); i++){
            // Parse the single contact
            contact_book.add(Contact.fromJSON( contacts.getJSONObject(i) ));
        }

        // Print what you have:
        for (Contact c : contact_book)
            System.out.println(c);

        // And vise versa:
        JSONArray json_arr = new JSONArray();
        for (Contact c : contact_book)
            json_arr.put(c.toJSON());
        System.out.println(json_arr.toString());
    }

    public static class Contact {
        // Fields and toString()-method omitted!

        public static Contact fromJSON(JSONObject json) throws JSONException {
            Contact instance = new Contact();
            instance.name = json.getString("name");
            instance.group = json.getString("group");
            // Recursively parse the numbers:
            JSONArray numbers = json.getJSONArray("numbers");
            instance.numbers = new Number[numbers.length()];
            for (int i = 0; i < numbers.length(); i++){
                instance.numbers[i] = Number.fromJSON(numbers.getJSONObject(i));
            }
            return instance;
        }

        public JSONObject toJSON(){
            try {
                JSONObject json = new JSONObject();
                json.put("name", name);
                json.put("group", group);
                JSONArray numbers_arr = new JSONArray();
                for (Number n : numbers)
                    numbers_arr.put(n.toJSON());
                json.put("numbers", numbers_arr);
                return json;
            } catch (JSONException e) {
                // Design error. See "Number"s toJSON()-method.
                throw new RuntimeException(e);
            }
        }

    }

    public static class Number {
        // Fields and toString()-method omitted!

        public static Number fromJSON(JSONObject json) throws JSONException {
            Number instance = new Number();
            instance.number = json.getInt("number");
            instance.type = json.getString("type");
            return instance;
        }

        public JSONObject toJSON(){
            try {
                JSONObject json = new JSONObject();
                json.put("number", number);
                json.put("type", type);
                return json;
            } catch (JSONException e) {
                // In my opinion, this is a design-error. JSONException shouldn't be used here,
                // because giving "null" for the key in put(String, XX) is a programming error,
                // hence a RuntimeException.
                throw new RuntimeException(e);
            }
       }

    }
}

As illustrated by this example, the JSON is processed “step-by-step”, just like the XML in DOM. The above code produces the same output as the code that uses gson.

My best-practice advice is to create a public static fromJSON(JSONObject) method for all classes which can be created from a JSON-string. This is then an alternative to using the constructor for creating a new instance. For those classes it makes sense to also add a public JSONObject toJSON()-method, which does it the other way around.

When to use what

From the previous examples it seems, that using “google-gson” is always the better idea, since it is easier for the developer. But, there is a situation (other then “you have to use org.json!”) where gson does not work: Environments with restricted permissions.

“google-gson” heavily relies on reflection to populate the instances with the values from JSON. One of the environments which restricts the access to the reflection-API is the Java Webstarter. When you start the above sample from a JNLP file, you get the following exception:

java.security.AccessControlException: access denied ("java.lang.reflect.ReflectPermission" "suppressAccessChecks")
    ...
    at java.lang.SecurityManager.checkPermission(Unknown Source)
    ...
    at com.google.gson.Gson.fromJson(Gson.java:678)
    at org.knuth.jsontest.GsonTest.main(GsonTest.java:11)

There is the important exception-information: The SecurityManager does not permit the ReflectPermission. The solution here: Either buy a certificate and sign your jar, or rather use the org.json-library which is not affected by this permission (since it doesn’t use any reflection).

Conclusion

JSON is the format to use when you’re creating an API for a webservice. That’s just a fact. It’s more readable then XML and less verbose. But you shouldn’t forget, that it is just a data-interchange language.

When parsing JSON, you can (and should if possible) use “google-gson”, as it takes away all the pain of implementing your own to/from JSON methods and gives you a powerful tool to parse even large and complex data-structures with ease.

However, in certain situations where gson is not an option, it’s always nice to know how to do it with a low-level library like the org.json-package, which is (apart from the above mentioned design-error) a very robust, but also explicit library.

Posted by Lukas Knuth

Comments

comments powered by Disqus