JSON parsing

All I wanted was to parse some JSON. Well, not just parse, but round trip objects to JSON to objects, and I wanted to do it automatically. Apparently this isn’t the goal of projects like Jackson and Gson. If you have a field that is an interface type or a list of objects, these libs don’t store the concrete types in the JSON and so cannot reconstruct the object graph. Seriously, wtf?! Xstream + Jettison might be able to do it, but Jettison is a bit of a strange monster and outputs ugly JSON. Plus I shouldn’t need a handful of libs for such a trivial task.

We now have some new classes in libgdx for reading and writing JSON. JsonWriter is a builder style API for emitting JSON:

There is also a class called XmlWriter that has a similar builder style API for emitting XML (note for better consistency with the new classes, I renamed the Xml class to XmlReader).

For reading JSON, there is a class cleverly called JsonReader, which uses a fancy pants Ragel parser, similar to the XmlReader.

Now we get to the cool part! There is a class named Json which internally makes use of JsonWriter and JsonReader to automatically go to and from Java and JSON:

This works by writing concrete class names in the JSON. This is only done when absolutely necessary, so the JSON output stays looking nice and clean most of the time.

I know this is reinventing the wheel and all that, but all three JSON classes total only ~500 lines of code. They solve using JSON for Java object serialization in ways other libraries don’t, and are likely more succinct. These classes aren’t the end all solution to Java + JSON (eg JsonReader doesn’t do streaming), but I think they cover the majority of needs.

In other news, you can now download the latest nightlies from this link, which doesn’t include the date.

12 thoughts on “JSON parsing

  1. I think that people who want a not-xml text serialization format also look at YAML for stuff like this, since it does preserve object types and can support arbitrary graphs.

  2. That is true, unfortunately YAML is very complicated to parse while JSON is super simple. I have a project called YamlBeans that is similar to my JSON stuff above, but for YAML:
    JSON is just a lot simpler. You’ll never see a YAML parser in ~200 lines of code.

  3. ObjectMap map = new Json().fromJson(ObjectMap.class, “{ \”moo\”: \”cow\” }”);

    I’ve been messing with the JSON stuff though, so update SVN (probably) tomorrow to get the new fancy stuff. 🙂

  4. Hi, I thought I’ll put it here first before opening a thread on the forum.

    I have the following problem:

    If I create a JsonWriter object, it works fine on the PC, but it crashes immediately on android. To reproduce it, just use the helloworld project and add these 2 lines:

    StringWriter json = new StringWriter();
    JsonWriter writer = new JsonWriter(json);

    It will start just fine on the PC (and you can work with it fine), but will crash on android.

    I hope you can help me with that.

  5. Kennyal, your problem can’t be the code you posted. The StringWriter constructor is always safe and the JsonWriter constructor only assigns a field, so can’t possibly crash. Likely you have a project setup problem. Please post the exception you get on the forums and we’ll try to help you out. 🙂

  6. Thanks, but I resolved it already. So for people googling this in 2 years, the problem was that the class java.util.ArrayDeque couldnt be found, cause you need API level 9 for it. But since that kills about 55% of the devices out there, I wont use it.
    Maybe you can write a version without it sometimes.

    Anyway, thanks.

  7. Assertion that ability to embed class name in JSON is not supported by Jackson is incorrect: Jackson can do this as well. There are 2 mechanisms for it; either annotation-based (to denote types that require polymorphic handling), or global (“default typing”). Latter is more similar to what is being described here.

    Now, while I understand your wanting to implement higher-level abstractions (builder, data binder), surely you could have reused one of dozens of existing JSON readers and writers, many of which are fully streaming. Not only do both Jackson and GSON provide such pieces (as subset of full jars), but there are multiple others available from org.json. Some of them have size in hundreds of lines, although I’m not sure size of parser source code should matter too much.

  8. Kennyal, ArrayDeque is gone.

    Hi Tatu, you’re everywhere! 😉 I’m the Kryo author BTW. I’m interested in automatic serialization of arbitrary classes, so annotations are out. You’re right, apparently Jackson can indeed output type information. I read about “TypeReference” but missed that feature. It seems “default typing” has a flag to output types for all objects. My Json class differs in that it only writes the class when it is needed for deserialization.

    GSON is very explicit in their docs that they don’t support this. It makes me wonder how useful a serialization lib is if it can’t round trip simple graphs…

    Implementing a parser and emitter was not much code, and I get exactly the features I want, and no more. Doing it myself also lets me support “JavaScript” and “minimal” JSON-like formats (basically JSON with fewer quotes). Typically output from my high level Json class is intended to be read back by the same class, so it doesn’t matter if it is valid JSON (though that is also supported).

    I mentioned the low lines of code to help excuse my wheel reinvention, and in reference to YAML, which is very hard to parse.

    I wrapped up my JSON stuff and made it available outside of libgdx on Google Code, called JsonBeans (to compliment my YamlBeans project).

  9. Hi,
    I was doing some tests using the JSON class and I ended up finding something wrong… I wrote down the simplest possible code to show you the problem:

    ComplexType complexObj = new ComplexType();
    complexObj.someString = “This is a test”;
    complexObj.innerComplex = new ComplexType();
    complexObj.someInt = 12;
    Json jsonTranslator = new Json();
    String json = jsonTranslator.toJson(complexObj, ComplexType.class);

    where ComplexType has just those 3 fields: someString, innerComplex and someInt.

    Running this code, the json variable contains the following string:
    someString: “This is a test”,
    innerComplex: {}
    The someInt field is missing. Probably the innerComplex field has something to do with it because if I comment the line that set this field everything works fine. And if I add and set more fields there is always only one missing in the json output.

    I hope this helps…
    Thank you for the work you have done so far

Leave a Reply

Your email address will not be published.