ln.json/JSONConverter.cs

367 lines
8.1 KiB
C#

using System;
using System.Collections.Generic;
using System.Globalization;
using sharp.json.attributes;
using System.Reflection;
using sharp.extensions;
namespace sharp.json
{
public static class JSONConverter
{
delegate object ConvertToDelegate(Type t,JSON json);
static Dictionary<Type, ConvertToDelegate> toDelegates = new Dictionary<Type, ConvertToDelegate>{
{ typeof(string), (t, json) => json.String },
{ typeof(int), (t, json) => (int)json.Integer },
{ typeof(short), (t, json) => (short)json.Integer },
{ typeof(long), (t, json) => json.Integer },
{ typeof(uint), (t, json) => (uint)json.Integer },
{ typeof(ushort), (t, json) => (ushort)json.Integer },
{ typeof(ulong), (t, json) => (ulong)json.Integer },
{ typeof(double), (t, json) => json.Double },
{ typeof(float), (t, json) => json.Double },
{ typeof(bool), (t, json) => json.Boolean },
{ typeof(DateTime), (t, json) => DateTime.Parse(json.String, CultureInfo.InvariantCulture) },
{ typeof(Guid), (t, json) => Guid.Parse(json.String)},
{ typeof(object), ToObject }
};
public static T To<T>(JSON json)
{
Type t = typeof(T);
return (T)(object)To(t, json);
}
public static JSON From(object value)
{
if (value == null)
{
return JSONSpecial.Null;
}
return From(value.GetType(), value);
}
public static object To(Type t,JSON json){
if (json.JSONType == JSONTypes.Null){
return null;
}
if (t.IsEnum){
return Enum.Parse(t, json.String);
}
if (toDelegates.ContainsKey(t))
{
return toDelegates[t](t, json);
}
if (t.IsArray){
return ToArray(t, json);
}
if (!t.IsPrimitive){
return ToObject(t, json);
}
throw new InvalidCastException(String.Format("JSON {0} can't be casted to {1}", json.JSONType.ToString(), t.Name));
}
public static void ApplyObject(JSON json, object o)
{
FieldPropertyInfo[] fpilist = fpi(o.GetType());
foreach (FieldPropertyInfo fpi in fpilist)
{
if (json.Contains(fpi.Key))
{
fpi.setValue(o, To(fpi.ValueType, json[fpi.Key]));
}
}
}
public static object ToObject(Type t,JSON json){
ConstructorInfo ci = t.GetConstructor(new Type[] { typeof(JSON) });
if (ci != null)
{
if (ci.GetParameters()[0].ParameterType.Equals(typeof(JSON)))
{
return Activator.CreateInstance(t, (object)json);
}
}
JSONClassPolicy cp = t.GetCustomAttribute<JSONClassPolicy>();
if (cp == null)
{
cp = new JSONClassPolicy();
}
return ToObject(t, json, cp.Policy);
}
private static object ToObject(Type t, JSON json,JSONPolicy policy)
{
object oi = Activator.CreateInstance(t);
ApplyObject(json,oi);
return oi;
}
private static object ToArray(Type t,JSON json)
{
Array a = Array.CreateInstance(t.GetElementType(), json.Count);
Type et = t.GetElementType();
JSONField jfield = t.GetCustomAttribute<JSONField>();
if (!jfield.IsNull())
{
et = jfield.ConstructWithType;
}
for (int n = 0; n < json.Count; n++)
{
a.SetValue(To(et ,json[n]), n);
}
return a;
}
public static JSON From(Type t, object value)
{
if (value == null)
{
return JSONSpecial.Null;
}
if (t == null)
{
t = value.GetType();
}
if ((t.IsPrimitive) || (t == typeof(string)))
{
return FromPrimitive(value);
}
if (t == typeof(DateTime))
{
return new JSONString(((DateTime)value).ToString(CultureInfo.InvariantCulture));
}
if (t == typeof(Guid))
{
return ((Guid)value).ToString();
}
if (t.IsEnum)
{
return new JSONString(value.ToString());
}
if (t.IsArray)
{
JSONArray ja = new JSONArray();
Array a = (Array)value;
Type et = t.GetElementType();
if (et == typeof(object))
{
et = null;
}
foreach (object e in a)
{
ja.Add(From(et, e));
}
return ja;
}
return FromObject(value);
}
public static JSON FromPrimitive(object value)
{
Type t = value.GetType();
if (typeof(int).Equals(t))
{
return new JSONNumber((int)value);
}
if (typeof(long).Equals(t))
{
return new JSONNumber((long)value);
}
if (typeof(double).Equals(t))
{
return new JSONNumber((double)value);
}
if (typeof(float).Equals(t))
{
return new JSONNumber((float)value);
}
if (typeof(string).Equals(t))
{
return new JSONString(value.ToString());
}
if (typeof(bool).Equals(t))
{
return ((bool)value) ? JSONSpecial.True : JSONSpecial.False;
}
throw new NotImplementedException(String.Format("Cast of {0} to JSON is not (yet) supported", t.Name));
}
public static JSON FromObject(object value)
{
return FromObject(value.GetType(), value);
}
public static JSON FromObject(Type type, object value)
{
Type t = value.GetType();
JSONObject jo = new JSONObject();
foreach (FieldPropertyInfo fpi in fpi(t)){
jo[fpi.Key] = JSON.From(fpi.getValue(value));
}
return jo;
}
private static FieldPropertyInfo[] fpi(Type t)
{
JSONClassPolicy cp = t.GetCustomAttribute<JSONClassPolicy>();
if (cp == null)
{
cp = new JSONClassPolicy();
}
return fpi(t, cp);
}
private static FieldPropertyInfo[] fpi(Type t,JSONClassPolicy cp)
{
BindingFlags bf;
switch (cp.Policy){
case JSONPolicy.ALL:
bf = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly;
break;
case JSONPolicy.ATTRIBUTED:
bf = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly;
break;
case JSONPolicy.NONPUBLIC:
bf = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.DeclaredOnly;
break;
default:
bf = BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly;
break;
}
List<FieldPropertyInfo> fpilist = new List<FieldPropertyInfo>();
foreach (FieldInfo fi in t.GetFields(bf))
{
fpilist.Add(new FieldPropertyInfo(fi));
}
foreach (PropertyInfo pi in t.GetProperties(bf))
{
if (pi.GetIndexParameters().Length == 0){
fpilist.Add(new FieldPropertyInfo(pi));
}
}
FieldPropertyInfo[] temp = fpilist.ToArray();
fpilist.Clear();
foreach (FieldPropertyInfo fpi in temp){
if ((cp.Policy != JSONPolicy.ATTRIBUTED) || (fpi.JSONField != null))
{
fpilist.Add(fpi);
}
}
if (!t.BaseType.IsNull()){
fpilist.AddRange(fpi(t.BaseType,cp));
}
return fpilist.ToArray();
}
struct FieldPropertyInfo
{
public String Key { get; set; }
FieldInfo FieldInfo { get; set; }
PropertyInfo PropertyInfo { get; set; }
public JSONField JSONField { get; set; }
public FieldPropertyInfo(PropertyInfo propertyInfo)
{
this.PropertyInfo = propertyInfo;
this.FieldInfo = null;
this.JSONField = propertyInfo.GetCustomAttribute<JSONField>();
this.Key = (this.JSONField == null) ? propertyInfo.Name : ((this.JSONField.Alias == null) ? propertyInfo.Name : this.JSONField.Alias);
}
public FieldPropertyInfo(FieldInfo fieldInfo)
{
this.PropertyInfo = null;
this.FieldInfo = fieldInfo;
this.JSONField = fieldInfo.GetCustomAttribute<JSONField>();
this.Key = (this.JSONField == null) ? fieldInfo.Name : ((this.JSONField.Alias == null) ? fieldInfo.Name : this.JSONField.Alias);
}
public void setValue(object inst, object value)
{
if (PropertyInfo != null)
{
if (PropertyInfo.SetMethod != null)
{
PropertyInfo.SetValue(inst, value);
}
}
else if (FieldInfo != null)
{
FieldInfo.SetValue(inst, value);
}
}
public object getValue(object inst)
{
if ((PropertyInfo != null)&&(!PropertyInfo.GetMethod.IsNull()))
{
return PropertyInfo.GetValue(inst);
}
else if (FieldInfo != null)
{
return FieldInfo.GetValue(inst);
}
return null;
}
public Type ValueType
{
get
{
if ((JSONField != null)&&(JSONField.ConstructWithType != null))
{
return JSONField.ConstructWithType;
}
if (PropertyInfo != null)
{
return PropertyInfo.PropertyType;
}
else if (FieldInfo != null)
{
return FieldInfo.FieldType;
}
return null;
}
}
}
}
}