JSON refactoring

libgdx has its own JSON parser, emitter, and reflection-based object serialization. I’ve never been happy with the parsing results being OrderedMaps and Arrays because it is so clunky to iterate over the data and get out the values you want. At one point I had a JsonMap and JsonArray classes, but it was too much of a mess. Recently I worked with cJSON, a JSON parser for C, and I liked the simplicity of its DOM. I was inspired have committed something similar for libgdx.

There is a new class called JsonValue. It is a single container that represents a JSON object, array, string, double, long, boolean, or null. You might think it strange that double and long are in the list since all numbers in JSON are floats, but these data types allow us to use JSON for object serialization without losing data. Anyway, JsonValue provides methods to get the value out as a specific type, pretty printing, and iteration. No more casting, pointy brackets, and verbose map iteration. Children are a doubly linked list and iterated this way:

JsonValue map = ...;
for (JsonValue entry = map.child(); entry != null; entry = entry.next())
    System.out.println(entry.name() + " = " + entry.asString());

Arrays and objects are treated the same, they both simply have children. The children values of an object can use name() to get the object key.

Convenience methods are provided to get the value or children of a child. Eg, getString(“name”) returns the value of the key “name” as a string. If not found, it throws an exception. With getString(“name”, “defaultValue”), the second parameter is returned if not found, instead of throwing an exception. The get(“name”) method returns a child as a JsonValue, or null if not found. require(“name”) does the same but throws an exception if not found. These methods remove the need for null checking while still allowing you to write code that fails properly for unexpected input.

So what does this mean for your code that uses libgdx’s JSON classes? Only reading JSON is affected. If you use JsonReader, you’ll get back a JsonValue instead of an OrderedMap. If you use the Json class for object serialization, you won’t be affected unless you were parsing into OrderedMaps. The Json.Serializer and Json.Serializable have changed slightly. My apologies if you have to make changes! The JsonValue class is fully documented and hopefully any changes you have to make are minor. GWT emulation has been updated. If you encounter bugs, please file an issue on the tracker and it will be fixed post-haste!

The libgdx JSON stuff is also available as JsonBeans for use outside of libgdx. The next thing I’ll do is allow KryoNet to use it for a human readable serialization format.

-Nate

14 thoughts on “JSON refactoring

  1. So nice, Refactoring is the most important work in a framework to improve quality and performance, thanks for that.

  2. I had done something like that for my code. Was even thinking in giving it back, but now I’m just gonna download it and refactor my code. Nice work. I had dropped OrderedMap and kept Array for arrays.

  3. Hehe, yeah except I forgot to fix Skin, and then when I fixed Skin my fix needed a fix. But I tried! I mean, I didn’t install the GWT plugins and actually test it, but I put forth a sort of half assed try and should be commended! 😉

  4. Not really, just needed a break from Spine runtimes. I have a KryoNet based on Netty that I would like to finish someday. That would be the only thing I really want to do with KryoNey. The Netty KryoNet works but is missing some regular KryoNet features, which is the tedious part of doing the conversion.

  5. I think this is the kind of stuff that would be better off libgdx. How is it related to game programming?

    I use GSON and I’m really happy with it. I feel like people who don’t need json shouldn’t have to bear a json parser in their .jar.

    Nonetheless, great work as usual 😉

  6. Hi Nate,

    I loved the previous version of JSON and was using it a lot in my project.

    But since I upgraded to the latest version of libgdx I noticed a change with quite some impact…

    I use a lot of generic collections like OrderedMap<String, ObjectMap<String, Object>>, Array<ObjectMap<String, Object>>, etc.

    In the previous version I would get nice, clean, readable and compact JSON when writing:

    {
    name: classic3,
    objects: [
    {
    color: ffffa500,
    angle: -175.5051,
    x: 34,
    y: 25
    },
    ….

    In the new version I get a less readable result: (also quite an impact on the total size of the files)

    {
    name: classic3,
    objects: [
    {
    color: {
    class: java.lang.String,
    value: ffffa500
    },
    angle: {
    class: java.lang.Float,
    value: -175.49612
    },
    x: {
    class: java.lang.Float,
    value: 34
    },
    y: {
    class: java.lang.Float,
    value: 25
    },
    ….

    To work around this I took the previous versions of the JSON classes and placed them in a different package..

    Not the most elegant solution but it works, do you know a cleaner way to fix this?

    Keep up the great work!
    Thanx,

    Johan

Leave a Reply

Your email address will not be published.