Tuesday, April 8, 2014

Deserialize an anonymous type using SimpleJson

var json = "{\"name\": \"Joe\"," +
           "\"age\": 25," +
           "\"address\": {\"city\": \"Paris\"}," +
           "\"emails\": [\"joe@home.com\", \"joe@work.com\"]," +
           "\"phones\": [{\"type\": \"Mobile\", \"number\": \"555 1234\"}]}";
var prototype = new
    {
        name = default(string),
        age = default(int),
        address = new {city = default(string)},
        emails = new string[0],
        phones = new[] {new {type = default(string), number = default(string)}}
    };
var result = SimpleJsonExt.DeserializeAnonymousObject(json, prototype);

using CacheEntry = KeyValuePair<ParameterInfo[], ReflectionUtils.ConstructorDelegate>;
public static class SimpleJsonExt
{
    public static T DeserializeAnonymousObject<T>(string json, T prototype)
    {
        return SimpleJson.SimpleJson.DeserializeObject<T>(json, new Strategy());
    }
    private class Strategy : PocoJsonSerializerStrategy
    {
        private readonly IDictionary<Type, CacheEntry> _ctorCache =
            new ReflectionUtils.ThreadSafeDictionary<Type, CacheEntry>(CreateConstructorDelegate);
        private static CacheEntry CreateConstructorDelegate(Type key)
        {
            var ctors = key.GetConstructors();
            if (ctors.Length == 1)
            {
                var ctor = ctors[0];
                var parms = ctor.GetParameters();
                if (parms.Length > 0)
                {
                    return new CacheEntry(parms, ReflectionUtils.GetContructor(ctor));
                }
            }
            return default(CacheEntry);
        }
        public override object DeserializeObject(object value, Type type)
        {
            var dict = value as IDictionary<string, object>;
            if (dict != null)
            {
                var ctor = _ctorCache[type];
                if (ctor.Key != null)
                {
                    return ctor.Value(ctor.Key
                        .Select(param => DeserializeObject(
                            dict.TryGetValue(param.Name, out value) ? value : null,
                            param.ParameterType))
                        .ToArray());
                }
            }
            return base.DeserializeObject(value, type);
        }
    }
}
SimpleJson