forked from ln-dotnet/ln.json
367 lines
8.1 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|