Fork on Github
Download the Nuget package
The previous tutorial focused on serialising complex JSON objects. This tutorial describes the process of deserialisation using JSON#.
The purpose of JSON# is to allow memory-efficient JSON processing. At the root of this is the ability to dissect large JSON files and extract smaller structures from within, as discussed in Tutorial #1.
One thing, among many, that JSON.NET achieves, is allow memory-efficient JSON-parsing using the JsonTextReader
component. The last thing that I want to do is reinvent the wheel; to that end, JSON# also provides a simple means of deserialisation, which wraps JsonTextReader. Using JsonTextReader
alone, requires quite a lot of custom code, so I’ve provided a wrapper to make things simpler and allow reusability.
At the root of the deserialization process lies the StandardJsonNameValueCollection
class. This is an implementation of the JsonNameValueCollection
, from which custom implementations can be derived, if necessary, in a classic bridge design, leveraged from the Deserialiser
component. Very simply, it reads JSON node values and stores them as key-value pairs; they key is the node’s path from root, and the value is the node’s value. This allows us to cache the JSON object and store it in a manner that provides easy access to its values, without traversing the tree:
class StandardJsonNameValueCollection : JsonNameValueCollection { public StandardJsonNameValueCollection(string json) : base(json) {} public override NameValueCollection Parse() { var parsed = new NameValueCollection(); using (var reader = new JsonTextReader(new StringReader(json))) { while (reader.Read()) { if (reader.Value != null && !reader.TokenType.Equals(JsonToken.PropertyName)) parsed.Add(reader.Path, reader.Value.ToString()); } return parsed; } } }
Let’s work through an example using our SimpleObject class from previous tutorials:
class SimpleObject : IHaveSerialisableProperties { public string Name { get; set; } public int Count { get; set; } public virtual SerialisableProperties GetSerializableProperties() { return new SerialisableProperties("simpleObject", new List { new StringJsonProperty { Key = "name", Value = Name }, new NumericJsonProperty { Key = "count", Value = Count } }); } }
Consider this class represented as a JSON object:
{ "simpleObject": { "name": "SimpleObject", "count": 1 } }
The JSON# JsonNameValueCollection
implementation will read each node in this JSON object and return the values in a NameValueCollection. Once stored, we need only provide a mechanism to instantiate a new SimpleObject POCO with the key-value pairs. JSON# provides the Deserialiser
class as an abstraction to provide this functionality. Let’s create a class that accepts the JsonNameValueCollection
and uses it to populate an associated POCO:
class SimpleObjectDeserialiser : Deserialiser { public SimpleObjectDeserialiser(JsonNameValueCollection parser) : base(parser) {} public override SimpleObject Deserialise() { var properties = jsonNameValueCollection.Parse(); return new SimpleObject { Name = properties.Get("simpleObject.name"), Count = Convert.ToInt32(properties.Get("simpleObject.count")) }; } }
This class contains a single method designed to map properties. As you can see from the code snippet above, we read each key as a representation of corresponding node’s path, and then bind the associated value to a POCO property.
JSON# leverages the SimpleObjectDeserialiser as a bridge to deserialise the JSON string:
const string json = "{\"simpleObject\":{\"name\":\"SimpleObject\",\"count\":1}}"; var simpleObjectDeserialiser = new SimpleObjectDeserialiser(new StandardJsonNameValueCollection(json)); var simpleObject = Json.Deserialise(_simpleObjectDeserialiser);
So, why do this when I can just bind my objects dynamically using JSON.NET:
JsonConvert.DeserializeObject(json);
There is nothing wrong with deserialising in the above manner. But let’s look at what happens. First, it will use Reflection to look up CLR metadata pertaining to your object, in order to construct an instance. Again, this is ok, but bear in mind the performance overhead involved, and consider the consequences in a web application under heavy load.
Second, it requires that you decorate your object with serialisation attributes, which lack flexibility in my opinion.
Thirdly, if your object is quite large, specifically over 85K in size, you may run into memory issues if your object is bound to the Large Object Heap.
Deserialisation using JSON#, on the other hand, reads the JSON in stream-format, byte-by-byte, guaranteeing a small memory footprint, nor does it require Reflection. Instead, your custom implementation of Deserialiser
allows a greater degree of flexibility when populating your POCO, than simply decorating properties with attributes.
I’ll cover deserialising more complex objects in the next tutorial, specifically, objects that contain complex properties such as arrays.
Connect with me:
Nice review. I actually developed my own library for some of the reasons that you mentioned (along with some others). I’d love to hear your thoughts on Manatee.Json (source available on BitBucket).
I have my own version of your IHaveSerializableProperties called IJsonSerializable. That’s where I started, but I didn’t want to limit my users to it, so I added reflection-based serialization as well. From there, I just kept adding features.
Thanks Dennis, I appreciate your comment. I’d certainly be interested to have a look at your library.
Hi, While this is a great article regarding de-serializing object without using reflection. However JsonSerializer already has caching the properties of a class, so it doesn’t use reflection every single time, and it handles the deserialisation using JsonTextReader so it does deserialise in chunks as well.
I may be wrong here, but please let me know your thoughts on this.
Thank you for your valuable time.
Thanks for your comment. Yes, the point of the article and the associated library is to promote the concept of leveraging JsonTextReader to avail of speed.