RSS

Micro-JSON for Netduino (and PC)

06 Mar

JSON logoThis is a pretty useful tool for the Netduino, which I need for playing around some Micro-WPF demo on the Eve board.
As soon you want to deal with web-services, JSON is a must-have format for serializing data. Although Netduino does not use Javascript, the JSON format is very compact, at least when compared to XML. By the way, XML is richer as structure and schema, and JSON is sometimes blurry about the data format (e.g. date and time).
The small software library comes with both a parser and a serializer. The parser rules strictly rely on the specification as in the official JSON portal.
The parser deserializes a JSON string to a DOM of specific objects. I’ve been deeply inspired by the JLinq of the awesome library JSON.Net by James Newton-King.

The problem.

Create a JSON parser isn’t a really complex task, unless you have to work on very-low resources devices. In that case, everything should be optimized at best.
My first attempt to create a decent parser and serializer was successful, but the result was not what I’d expected. Although the code runs surprisingly fast on a normal PC, on the Netduino Plus 2 runs pretty slow and takes a lot (i.e. too much) RAM. That leaded me to adjust and optimized several parts of the code, at least to solve the memory occupation issue. The second release is pretty better.

How it works.

The approach is functional-like, although it’s normal C# highly optimized for low-resources platform. However, the same code works on any .Net platform without any problem.
As stated, the first attempt wasn’t the best one. I used several resource-heavy components, which de-facto prohibits the usage on the Netduino. So, it turned to a different yet trivial solution using as less resources as possible. Not sure that’s the very best achievement possible, though.

For instance, here is the piece of code to parse a JSON string, as used in the first release:

        private static JsonParserContext ConsumeString(
            this JsonParserContext ctx,
            bool throws
            )
        {
            var src = ctx.Source;
            JsonParserContext rtn;
            if ((rtn = ctx.ConsumeWhiteSpace().ConsumeAnyChar("\"", throws)).IsSucceeded)
            {
                var sb = new StringBuilder();

                for (int p = src.Position, len = src.Text.Length; p < len; p++)
                {
                    char c;
                    if ((c = src.Text[p]) == '"')
                    {
                        src.Position = p + 1;
                        break;
                    }
                    else
                    {
                        sb.Append(c);
                    }
                }

                rtn.SetResult(
                    new JValue { BoxedValue = sb.ToString() }
                    );
            }

            return rtn;
        }

Below is how it is the new improved version. Notice that there’s no more the StringBuilder object, and it avoids the creation of new JsonParserContext instances on every call.

        private static JsonParserContext ConsumeString(
            this JsonParserContext ctx,
            bool throws
            )
        {
            if (ctx.ConsumeWhiteSpace().ConsumeAnyChar("\"", throws).IsSucceeded)
            {
                JSonReader src = ctx.Begin();

                for (int p = src.Position, len = src.Text.Length; p < len; p++)
                {
                    if ((src.Text[p]) == '"')
                    {
                        ctx.SetResult(
                            new JValue { BoxedValue = src.Text.Substring(src.Position, p - src.Position) }
                            );

                        src.Position = p + 1;
                        break;
                    }
                }
            }

            return ctx;
        }

Another great improvement (in terms of resource savings) is about the way to store the key-value pairs in a JSON object.
The first attempt uses the Hashtable object, which comes with any .Net platform, and it’s tailored for such purpose. However, its O(1)-access ability comes with a price in terms of resources, and it’s too high to afford for a Netduino.
The more-trivial solution of a simple array requires much less resources, but the data access now takes O(N).

Performance.

I performed the test with several JSON strings. The longest is about 9kiB, while the shortest is roughly 500 bytes.
Using the first release, the longest string is almost impossible to parse: the parser runs out of RAM very quickly.

Here are some results.
In the following picture there is the complete JSON “roundtrip” (parsing+serializing) of the shortest string (about 500 bytes), using the FIRST release.
The upper plot shows the parsing duration (high level) and takes about 170ms to complete. The serialization of the resulting object is way faster and requires a little more than 20ms (lower plot).

UNIT0000

Hereinafter, the charts are all related to the SECOND library release.
Here is the same 500 bytes-string parsed then serialized. Despite on the PC the revision takes a little longer to perform, on the Netduino is a little faster instead. I suppose all the benefits derive from the less RAM usage.

UNIT0001

Here is a 2kiB-JSON parsed, which takes almost 1.2 seconds to perform. The serialzation is not shown here.

UNIT0003

Finally, the “huge” 9kiB-JSON taking looooong to parse: almost 25 seconds!!!. There’s no serialization in this chart, because after a while the Netduino runs out of RAM. I believe there’s something to trim yet…

UNIT0002

The J-DOM.

I don’t know how to call it. The reference JSON.Net library where I inspired from offers a complete DOM support together with Linq, but that’s not possible in a tiny context as the Micro Framework is. By the way, the DOM I defined is JSON-specific: is the result of the serialization, and allows to manipulate the resulting object with ease. Once the DOM is complete, you can serialize it to have back a JSON string.
As stated, a must-have tool for any web-related application.

The usage is very simple and it’s the same as the JSON.Net’s JLinq (except for the Linq!).
Given this sample JSON string (as from Wikipedia):

{
    "firstName": "John",
    "lastName": "Smith",
    "age": 25,
    "address": {
        "streetAddress": "21 2nd Street",
        "city": "New York",
        "state": "NY",
        "postalCode": 10021
    },
    "phoneNumbers": [
        {
            "type": "home",
            "number": "212 555-1234"
        },
        {
            "type": "fax",
            "number": "646 555-4567"
        }
    ]
}

Here is some example of manipulation from within your C# code:

            var jdom = (JObject)JsonHelpers.Parse(s);

            Console.WriteLine((int)jdom["age"]);    //displays 25

            //add a new phone entry
            var jentry = new JObject();
            jentry["type"] = "mobile";
            jentry["number"] = "+39-123-456-7890";

            var jphones = (JArray)jdom["phoneNumbers"];
            jphones.Add(jentry);

            string jtxt = JsonHelpers.Serialize(jdom);
            Console.WriteLine(jtxt);

Okay, take me to the source code…

Here is the link with two complete Visual Studio solutions: both regular .Net and Netduino MF. The source contains also the first release of the parser, although it is not used.

About these ads
 
2 Comments

Posted by on March 6, 2014 in .Net, Software

 

Tags: , , ,

2 responses to “Micro-JSON for Netduino (and PC)

  1. Georgi

    April 11, 2014 at 3:56 pm

    Great post Mario, well done!

     
  2. Compulim

    May 21, 2014 at 5:23 pm

    Handy and easy! You made the missing piece for my hobby project that talk to my Windows Phone! Thanks!

     

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.

Join 85 other followers

%d bloggers like this: