JSON.NET Custom Converters–A Quick Tour

I have to admit that I’m a basic user when it comes to JSON serialization/deserialization.  I’ve used JSON.NET and the DataContractJsonSerializer.  I’ve read that JSON.NET is faster and more efficient than the built-in .NET serializer, but I haven’t had to build a system that is dependent on squeezing microseconds out of my serialization routines.  That said, I do prefer JSON.NET because it is more flexible when it comes to using DataContractAttribute and DataMemberAttribute for customizing your JSON output.

So I came across an interesting question on StackOverflow today, asking how a json string like:

{‘one’: 1, ‘two’: 2, ‘three’: 3, ‘four’: 4, ‘blah’: 100}

would have its “one” and “two” properties deserialized to an object’s One and Two properties (easy) and anything else in the json string would be dumped into a Dictionary<string,object> (hmmm…not so easy).  So the resulting object would look like:

Mapped mappedObj = { 
  One = 1; 
  Two = 2; 
  TheRest = [{three=3}, {four=4}, {blah=100}]'; 
}

I’ve read about custom JSON.NET converters, but had never written one.  So I decided to give it a shot and discovered that it’s really not too bad.  Here’s my sample code:

using System;
using System.Collections.Generic;
using System.Linq;

using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System.Reflection;

namespace JsonConverterTest1
{
    public class Mapped
    {
        private Dictionary<string, object> _theRest = new Dictionary<string, object>();
        public int One { get; set; }
        public int Two { get; set; }
        public Dictionary<string, object> TheRest { get { return _theRest; } }
    }

    public class MappedConverter : CustomCreationConverter<Mapped>
    {
        public override Mapped Create(Type objectType)
        {
            return new Mapped();
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            var mappedObj = new Mapped();
            //get an array of the object's props so I can check if the JSON prop s/b mapped to it
            var objProps = objectType.GetProperties().Select(p => p.Name.ToLower()).ToArray();

            //loop through my JSON string
            while (reader.Read())
            {
                //if I'm at a property...
                if (reader.TokenType == JsonToken.PropertyName)
                {
                    //convert the property to lower case
                    string readerValue = reader.Value.ToString().ToLower();
                    if (reader.Read())  //read in the prop value
                    {
                        //is this a mapped prop?
                        if (objProps.Contains(readerValue))
                        {
                            //get the property info and set the Mapped object's property value
                            PropertyInfo pi = mappedObj.GetType().GetProperty(readerValue, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
                            var convertedValue = Convert.ChangeType(reader.Value, pi.PropertyType);
                            pi.SetValue(mappedObj, convertedValue, null);
                        }
                        else
                        {
                            //otherwise, stuff it into the Dictionary
                            mappedObj.TheRest.Add(readerValue, reader.Value);
                        }
                    }
                }
            }
            return mappedObj;
        }
    }

    public class Program
    {
        static void Main(string[] args)
        {
            //a sample JSON string to deserialize
            string json = "{'one':1, 'two':2, 'three':3, 'four':4}";

            //call DeserializeObject, passing in my custom converter
            Mapped mappedObj = JsonConvert.DeserializeObject<Mapped>(json, new MappedConverter());

            //output some of the properties that were stuffed into the Dictionary
            Console.WriteLine(mappedObj.TheRest["three"].ToString());
            Console.WriteLine(mappedObj.TheRest["four"].ToString());
        }
    }
}

It’s pretty simple to create a custom converter and it’s almost limitless as to what you can do with it.

Of course, my sample code above is pretty simple and doesn’t take into account arrays or nested objects in the JSON string; but, that can be accounted for by using the JsonToken enumeration (which I do above in detecting a property) and checking for the start of a nested object or an array.

I found this an interesting exercise and gave me an opportunity to take a tour of a feature in JSON.NET that I’ve read about but never used.  I hope you find it interesting.

posted @ Tuesday, July 26, 2011 1:22 PM
Print

Comments on this entry:

# re: JSON.NET Custom Converters–A Quick Tour

Left by Tero at 10/22/2013 4:57 AM
Gravatar
Thank you very much for the article, it was of great help!

Your comment:



(not displayed)

 
 
 
 
 

Live Comment Preview:

 
«September»
SunMonTueWedThuFriSat
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011