Created
July 22, 2010 03:52
-
-
Save lukencode/485545 to your computer and use it in GitHub Desktop.
Alternate RestSharp Json Deserializer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Globalization; | |
using System.Linq; | |
using Newtonsoft.Json.Linq; | |
using RestSharp; | |
using RestSharp.Deserializers; | |
using RestSharp.Extensions; | |
namespace Shared.Utilities | |
{ | |
public class ExtendedJsonDeserializer : IDeserializer | |
{ | |
public string RootElement { get; set; } | |
public string Namespace { get; set; } | |
public string DateFormat { get; set; } | |
public T Deserialize<T>(RestResponse response) where T : new() | |
{ | |
var target = new T(); | |
if (target is IList) | |
{ | |
var objType = target.GetType(); | |
JArray json = JArray.Parse(response.Content); | |
target = (T)BuildList(objType, json.Root.Children()); | |
} | |
else | |
{ | |
JObject json = JObject.Parse(response.Content); | |
JToken root = json.Root; | |
if (RootElement.HasValue()) | |
root = json[RootElement]; | |
Map(target, root); | |
} | |
return target; | |
} | |
private void Map(object x, JToken json) | |
{ | |
var objType = x.GetType(); | |
var props = objType.GetProperties().Where(p => p.CanWrite).ToList(); | |
foreach (var prop in props) | |
{ | |
var type = prop.PropertyType; | |
var name = prop.Name; | |
var value = json[name]; | |
var actualName = name; | |
if (value == null) | |
{ | |
// try camel cased name | |
actualName = name.ToCamelCase(); | |
value = json[actualName]; | |
} | |
if (value == null) | |
{ | |
// try lower cased name | |
actualName = name.ToLower(); | |
value = json[actualName]; | |
} | |
if (value == null) | |
{ | |
// try name with underscores | |
actualName = name.AddUnderscores(); | |
value = json[actualName]; | |
} | |
if (value == null) | |
{ | |
// try name with underscores with lower case | |
actualName = name.AddUnderscores().ToLower(); | |
value = json[actualName]; | |
} | |
if (value == null || value.Type == JTokenType.Null) | |
{ | |
continue; | |
} | |
// check for nullable and extract underlying type | |
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) | |
{ | |
type = type.GetGenericArguments()[0]; | |
} | |
prop.SetValue(x, CreateType(value, type), null); | |
} | |
} | |
private object CreateAndMap(Type type, JToken element) | |
{ | |
object instance = null; | |
if (type.IsGenericType) | |
{ | |
var genericTypeDef = type.GetGenericTypeDefinition(); | |
if (genericTypeDef == typeof(Dictionary<,>)) | |
{ | |
instance = BuildDictionary(type, element.Children()); | |
} | |
else if (genericTypeDef == typeof(List<>)) | |
{ | |
instance = BuildList(type, element.Children()); | |
} | |
} | |
else | |
{ | |
instance = Activator.CreateInstance(type); | |
Map(instance, element); | |
} | |
return instance; | |
} | |
private IDictionary BuildDictionary(Type type, JEnumerable<JToken> elements) | |
{ | |
var dict = (IDictionary)Activator.CreateInstance(type); | |
var valueType = type.GetGenericArguments()[1]; | |
foreach (JProperty child in elements) | |
{ | |
var key = child.Name; | |
var item = CreateAndMap(valueType, child.Value); | |
dict.Add(key, item); | |
} | |
return dict; | |
} | |
private IList BuildList(Type type, JEnumerable<JToken> elements) | |
{ | |
var list = (IList)Activator.CreateInstance(type); | |
var itemType = type.GetGenericArguments()[0]; | |
foreach (var element in elements) | |
{ | |
list.Add(CreateType(element, itemType)); | |
} | |
return list; | |
} | |
private object CreateType(JToken obj, Type type) | |
{ | |
object returnObj = null; | |
if (type.IsPrimitive) | |
{ | |
// no primitives can contain quotes so we can safely remove them | |
// allows converting a json value like {"index": "1"} to an int | |
var tmpVal = obj.ToString().Replace("\"", string.Empty); | |
returnObj = tmpVal; | |
} | |
else if (type == typeof(string)) | |
{ | |
string raw = obj.ToString(); | |
// remove leading and trailing " | |
string clean = raw.Substring(1, raw.Length - 2); | |
returnObj = clean; | |
} | |
else if (type == typeof(DateTime)) | |
{ | |
DateTime dt; | |
if (DateFormat.HasValue()) | |
{ | |
var clean = obj.ToString().RemoveSurroundingQuotes(); | |
dt = DateTime.ParseExact(clean, DateFormat, CultureInfo.InvariantCulture); | |
} | |
else | |
{ | |
// try parsing instead | |
dt = obj.ToString().ParseJsonDate(); | |
} | |
returnObj = dt; | |
} | |
else if (type == typeof(Decimal)) | |
{ | |
var dec = Decimal.Parse(obj.ToString()); | |
returnObj = dec; | |
} | |
else if (type == typeof(Guid)) | |
{ | |
string raw = obj.ToString(); | |
var guid = new Guid(raw.Substring(1, raw.Length - 2)); | |
returnObj = guid; | |
} | |
else if (type.IsGenericType) | |
{ | |
var genericTypeDef = type.GetGenericTypeDefinition(); | |
if (genericTypeDef == typeof(List<>)) | |
{ | |
var list = BuildList(type, obj.Children()); | |
returnObj = list; | |
} | |
else if (genericTypeDef == typeof(Dictionary<,>)) | |
{ | |
var keyType = type.GetGenericArguments()[0]; | |
// only supports Dict<string, T>() | |
if (keyType == typeof(string)) | |
{ | |
var dict = BuildDictionary(type, obj.Children()); | |
returnObj = dict; | |
} | |
} | |
} | |
else | |
{ | |
var item = CreateAndMap(type, obj); | |
returnObj = item; | |
} | |
return returnObj; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment