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 toDelegates = new Dictionary{ { 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(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(); 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(); 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(); 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 fpilist = new List(); 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(); 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(); 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; } } } } }