Stringtree JSON

What is Stringtree JSON ?

Stringtree JSON is a small, neat and robust Java implementation of a reader, writer, and validator for the JSON (JavaScript Object Notation) data format. The reader and writer are one class each, with no dependencies at all. Even the full stringtree JSON jar with reader, writer, validator and some other useful classes weighs in at just 13kB!

This project was started when I was looking for an alternative to bloated and clumsy SOAP web services for a simple remote procedure call (RPC) interface to connect two Java applications. I looked around the internet but the only Java implementations I found at the time seemed huge (hundreds or even thousands of lines of code) and required the inclusion of other large jar files in order to use them. At that point I resolved to write my own implementation which would exactly match the JSON spec and have absolutely no external dependencies. This project is the result

What can I use it for?

JSON is a concise and largely human-readable representation of a wide range of structured data. Data stored or transferred as JSON can be read and written by code in a wide range of programming languages. Example uses include:

And many more possibilities...

What does Stringtree JSON include?

The Stringtree JSON components consist of three key classes, referred to sometimes as the JSON trilogy:

JSONReader and JSONWriter can be used completely stand-alone. If your data is being automatically generated and you already know that it is valid, that's all you need.

If you are not so sure about the validity of the JSON text your application may receive, or are worried about the validity of JSON generated by your application, you can use the JSONValidator. When the JSONValidator runs, it needs some way of displaying any errors it encounters. To allow maximum flexibility, it accepts an object which implements the JSONErrorListener interface. A few example implementations are provided for convenience:

Two convenience classes are also provided to simplify the case where you always want to validate:

How do I use Stringtree JSON?

I'll give a few simple examples here to get you started, but I strongly recommend checking out the Stringtree JSON unit test suite for a deeper understanding of what is possible and what to expect. Stringtree JSON was developed using Test-Driven Development, so the tests exercise every facility of the software.

JSONReader examples

First a very simple example. The text string "true" is valid JSON, and (naturally enough) represents the boolean value TRUE. To show that the JSONReader works, just grab the source file from subversion, or include stringtree-json.jar, stringtree.jar or mojasef.jar in your classpath. Then you can do stuff like:

import org.stringtree.json.JSONReader;

class JSONReaderExample {
  JSONReader reader = new JSONReader();

  public void example() {
    Object result = reader.read("true");
    System.out.println("JSONReader result is " + result +
      " of class " + result.getClass());
  }
}

In many ways that's all there is to it. Just pass in a text string containing some JSON, and the reader will return a Java object resulting from parsing the JSON. All that varies is the type of the returned object.

Within a JSON "object" or "array", each element also follows the above rules, so (for example) the JSON string

would be returned as an ArrayList with four entries. The first entry would be a Long, the second a String, the third a Boolean, and the fourth would be null.

Using the JSONValidatingReader is very similar. If you are happy to use the default ErrorListener (which writes its error log to the standard output stream), then usage is identical to the non-validating reader:

import org.stringtree.json.JSONValidatingReader;

class JSONValidatingReaderExample {
  JSONReader reader = new JSONValidatingReader();

  public void example() {
    Object result = reader.read("true");
    System.out.println("JSONReader result is " + result +
      " of class " + result.getClass());
  }
}

The only difference to be aware of is that the JSONVallidatingReader returns a special object (JSONValidatingReader.INVALID) if the JSON text is not valid.

To specify a different ErrorListener, just pass it in to the JSONValidatingReader constructor:

import org.stringtree.json.JSONValidatingReader;

class JSONValidatingReaderExample {
  JSONReader reader = new JSONValidatingReader(
    new ExceptionErrorListener());

  public void example() {
    Object result = reader.read("true");
    System.out.println("JSONReader result is " + result +
      " of class " + result.getClass());
  }
}

JSONWriter examples

To start the JSONWriter examples, let's show the converse of the first JSONReader example:

import org.stringtree.json.JSONWriter;

class JSONWriterExample {
  JSONWriter writer = new JSONWriter();

  public void example() {
    System.out.println("JSONWriter result is " + writer.write(true));
  }
}

Avoiding surprises when using the JSONWriter is a little more tricky than with the JSONReader. Java has a much richer type structure than JSON, so any conversion from Java to JSON is bound to include some limitations. Stringtree JSON tries to convert as intelligently as it can, by applying the following sequence of rules:

  1. If the Java object is null, generate a JSON null.
  2. If the Java object is a Boolean, generate a JSON true or false.
  3. If the Java object is a Number (such as an Integer, Double, etc), generate a JSON "number".
  4. If the Java object is a String or a single character, generate a JSON "string"
  5. If the Java object is a Map, generate a JSON "object" with the Map entries as elements.
  6. If the Java object is an array, an iterator, or an iterable collection, generate a JSON "array"
  7. Otherwise, treat the supplied object as a JavaBean, and generate a JSON "object" with the bean properties as elements.

One important consideration is that of cyclic references. In Java it is quite feasible for objects to refer to each other in a cyclic manner. For example, object a refers to object b, which in turn refers to object c, which refers back to object a. JSON has no support for such cyclic references, so the JSONWriter is unable to write them. Whenever the JSONWriter detects that an object element or property refers to an object which has already been written, it will generate a JSON null. If your application requires that such cyclic relationships are preserved, then JSON is probably not a good data format to use.

One more consideration is that of whether the class name of a JavaBean should be treated as a property and generated as an element in the resulting JSON text. All Java objects provide a getClass() method, which implies that all JavaBeans provide a readable "class" property. By default, the JSONWriter will include this class name as an element whenever it generates a JSON "object" from a JavaBean. You can switch off this behaviour by supplying a boolean false parameter to the JSONWriter constructor.

Using the JSONValidatingWriter is very similar. If you are happy to use the default ErrorListener (which writes its error log to the standard output stream), then usage is identical to the non-validating writer:

import org.stringtree.json.JSONValidatingWriter;

class JSONValidatingWriterExample {
  JSONReader reader = new JSONValidatingWriter();

  public void example() {
    System.out.println("JSONWriter result is " + writer.write(true));
  }
}

To specify a different ErrorListener, just pass it in to the JSONValidatingWriter constructor:

import org.stringtree.json.JSONValidatingWriter;

class JSONValidatingWriterExample {
  JSONReader reader = new JSONValidatingWriter(
    new ExceptionErrorListener());

  public void example() {
    System.out.println("JSONWriter result is " + writer.write(true));
  }
}

To override the default bean class name behaviour as well as specifying a different ErrorListener, pass the ErrorListener first, followed by the boolean:

import org.stringtree.json.JSONValidatingWriter;

class JSONValidatingWriterExample {
  JSONReader reader = new JSONValidatingWriter(
    new ExceptionErrorListener(), false);

  public void example() {
    System.out.println("JSONWriter result is " + writer.write(true));
  }
}

Does anyone actually use Stringtree JSON?

Stringtree JSON is used in at least one commercial application, and a slightly-modified version is included in a JSON plugin for the Struts 2 open source project (source code available from Google Code.)

If you or your project are using Stringtree JSON, and don't mind being listed here, please let me know and I'll add a name check and a link to your project web site.

Where can I find out more?

The full Stringtree source code (including JSON) and jar files are available from Sourceforge. There is also an occasional blog about Stringtree development, or just the posts about JSON.

The definitive web site about JSON is at www.json.org. There you can find a growing list of JSON implementations in a wide variety of languages and styles.

Who wrote this stuff, anyway?

The original code was written by Frank Carver. Suggestions, patches and bug reports gratefully recieved from:


Creative Commons License
This site is licensed under a Creative Commons License