Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
/* Copyright 2015, William Bundy */
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Contrabass.Sparse.Packaging
{
struct LoadContext
{
public Type Type;
public JObject Json;
public Package Package;
public string Name;
public int Depth;
public FieldInfo Field;
public object Target;
public bool ValidateField
{
get
{
var attr = Field.GetCustomAttribute(typeof(ValidateAttribute));
if(attr != null)
{
return true;
}
return false;
}
}
}
public class JsonLoader
{
public static Dictionary<Type, Dictionary<string, object>> Objects;
static JsonLoader()
{
Objects = new Dictionary<Type, Dictionary<string, object>>();
}
public static object LoadObject(Type type, JObject json, Package pkg, string name)
{
LoadContext context = new LoadContext();
context.Type = type;
context.Json = json;
context.Package = pkg;
context.Name = Validate(pkg, name);
return loadObjectWithContext(context);
}
private static object loadObjectWithContext(LoadContext context)
{
#region Error Checking
if (context.Type.GetCustomAttribute(typeof(JsonDefinedAttribute)) == null)
{
Console.WriteLine("Attempting to load non-json object! Problems may ensue.");
}
if (!Objects.ContainsKey(context.Type))
{
Objects[context.Type] = new Dictionary<string, object>();
}
var localObjects = Objects[context.Type];
if (localObjects.ContainsKey(context.Name))
{
return localObjects[context.Name];
}
#endregion
#region Inheritance and Overriding
var inheritProperty = context.Json.Property("Inherit");
object parent = null;
if(inheritProperty != null && inheritProperty.Value != null)
{
var inheritName = Validate(context.Package, inheritProperty.Value.ToString());
if(localObjects.ContainsKey(inheritName))
{
parent = localObjects[inheritName];
}
else
{
Console.WriteLine($"Can not find parent {inheritName} for {context.Name}");
}
}
var overrideProperty = context.Json.Property("Override");
if (overrideProperty != null && overrideProperty.Value != null)
{
var overrideName = Validate(context.Package, overrideProperty.Value.ToString());
if(localObjects.ContainsKey(overrideName))
{
context.Target = localObjects[overrideName];
}
else
{
Console.WriteLine($"Can not find override target {overrideName} for {context.Name}");
}
}
if (context.Target == null)
{
context.Target = Activator.CreateInstance(context.Type);
localObjects[context.Name] = context.Target;
}
#endregion
#region Field copying
var fields = context.Type.GetFields();
if (context.Type.GetProperty("Name") != null)
{
var nameProp = context.Type.GetProperty("Name");
var nameVal = nameProp.GetValue(context.Target);
if (nameVal != null && nameVal is string)
{
var nameStr = nameVal.ToString();
if(nameStr != "")
{
nameProp.SetValue(context.Target, context.Name);
}
}
}
foreach (var field in fields)
{
context.Field = field;
var property = context.Json.Property(field.Name);
if (property != null && property.Value != null)
{
setOn(context, convertJson(context, property));
}
else if(parent != null)
{
field.SetValue(context.Target, field.GetValue(parent));
}
}
#endregion
return context.Target;
}
private static void setOn(LoadContext context, object value)
{
try
{
context.Field.SetValue(context.Target, value);
}
catch(ArgumentException err)
{
}
}
private static object convertJson(LoadContext context, JProperty property)
{
JToken value = property.Value;
var fieldType = context.Field.FieldType;
switch (value.Type)
{
case JTokenType.Integer:
case JTokenType.Float:
case JTokenType.Boolean:
return JsonConvert.DeserializeObject(value.ToString());
break;
case JTokenType.String:
if (context.Type == typeof(string))
{
if(context.ValidateField)
{
return Validate(context.Package, value.ToString());
}
return value.ToString();
}
break;
case JTokenType.Object:
return LoadObject(
context.Field.FieldType,
(JObject)value,
context.Package,
context.Name + "." + property.Name);
break;
case JTokenType.Array:
if(fieldType.GetGenericTypeDefinition() == typeof(List<>))
{
List<object> l = new List<object>();
int i = 0;
foreach(var val in (JArray)value)
{
JProperty p = new JProperty($"{context.Name}.{property.Name}[{i}]", val);
l.Add(convertJson(context, p));
i++;
}
return l;
}
else if(fieldType.GetGenericTypeDefinition() == typeof(HashSet<>))
{
HashSet<object> l = new HashSet<object>();
int i = 0;
foreach (var val in (JArray)value)
{
JProperty p = new JProperty($"{context.Name}.{property.Name}[{i}]", val);
l.Add(convertJson(context, p));
i++;
}
return l;
}
else
{
var methods = fieldType.GetMethods(BindingFlags.Static).Where(
t => t.GetCustomAttribute(typeof(JsonArrayReprAttribute)) != null);
foreach(var method in methods)
{
object[] p = { (JArray)value };
return method.Invoke(null, p);
}
Console.WriteLine($"Could not convert {property.Name} on {context.Name}");
}
break;
}
return null;
}
public static string Validate(Package pkg, string name)
{
if(!name.Contains("."))
{
return pkg.Name + "." + name;
}
else
{
return name;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment