ln.json/ln.json/mapping/JSONMapper.cs

346 lines
13 KiB
C#

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
namespace ln.json.mapping
{
public delegate bool RequestCustomSerialization(object o, out JSONValue json);
public delegate bool RequestCustomUnserialization(JSONValue json, Type targetType, out object o);
public delegate bool RequestCustomMapping(Type targetType,out JSONMapping mapping);
public delegate bool MappingFactory(Type targetType, out JSONMapping mapping);
public class JSONMapper
{
public static JSONMapper DefaultMapper { get; set; } = new JSONMapper();
public event RequestCustomSerialization OnRequestCustomSerialization;
public event RequestCustomUnserialization OnRequestCustomUnserialization;
public event RequestCustomMapping OnRequestCustomMapping;
public JSONObjectMappingFlags DefaultMappingFlags { get; set; } = JSONObjectMappingFlags.PROPERTIES | JSONObjectMappingFlags.FIELDS;
public BindingFlags DefaultBindingFlags { get; set; } = BindingFlags.Instance | BindingFlags.Public;
public bool RequestCustomSerialization(object o, out JSONValue json)
{
foreach (RequestCustomSerialization rcs in OnRequestCustomSerialization?.GetInvocationList() ?? new RequestCustomSerialization[0])
{
if (rcs(o, out json))
return true;
}
json = null;
return false;
}
public bool RequestCustomUnserialization(JSONValue json, Type targetType, out object o)
{
foreach (RequestCustomUnserialization rcu in OnRequestCustomUnserialization?.GetInvocationList() ?? new RequestCustomUnserialization[0])
{
if (rcu(json, targetType, out o))
return true;
}
o = null;
return false;
}
public bool RequestCustomMapping(Type targetType, out JSONMapping mapping)
{
foreach (RequestCustomMapping rcm in OnRequestCustomMapping?.GetInvocationList() ?? new RequestCustomMapping[0])
{
if (rcm(targetType, out mapping))
return true;
}
mapping = null;
return false;
}
Dictionary<Type, JSONMapping> mappings = new Dictionary<Type, JSONMapping>();
public virtual void Add(JSONMapping mapping) => mappings[mapping.TargetType] = mapping;
Dictionary<Type, MappingFactory> mappingFactories = new Dictionary<Type, MappingFactory>();
public virtual void AddMappingFactory(Type targetType, MappingFactory mappingFactory) => mappingFactories.Add(targetType, mappingFactory);
public virtual bool GetOrBuildMapping(Type nativeType, out JSONMapping mapping) => TryGetMapping(nativeType, out mapping) || TryBuildRememberedMapping(nativeType, out mapping);
public virtual bool TryBuildRememberedMapping(Type nativeType,out JSONMapping mapping)
{
if (TryBuildMapping(nativeType, out mapping))
{
mappings.Add(nativeType, mapping);
return true;
}
return false;
}
public virtual bool TryBuildMapping(Type nativeType,out JSONMapping mapping)
{
if (nativeType.IsPrimitive)
{
mapping = null;
return false;
}
if (nativeType.IsArray)
{
mapping = new JSONArrayMapping(nativeType);
return true;
}
if (nativeType.IsSubclassOf(typeof(Exception)))
{
mapping = new JSONExceptionMapping(nativeType);
return true;
}
if ((mappingFactories.TryGetValue(nativeType, out MappingFactory mappingFactory)) && mappingFactory(nativeType, out mapping))
return true;
if (nativeType.IsGenericType)
{
Type genericTypeDefinition = nativeType.GetGenericTypeDefinition();
if (mappingFactories.TryGetValue(genericTypeDefinition, out mappingFactory) && mappingFactory(nativeType, out mapping))
return true;
if (genericTypeDefinition.Equals(typeof(IEnumerable<>)))
{
mapping = (JSONMapping)Activator.CreateInstance(typeof(JSONEnumerableMapping<>).MakeGenericType(nativeType.GetGenericArguments()[0]));
return true;
}
if (genericTypeDefinition.Equals(typeof(Dictionary<,>)))
{
mapping = (JSONMapping)Activator.CreateInstance(typeof(JSONDictionaryMapping<,>).MakeGenericType(nativeType.GetGenericArguments()));
return true;
}
}
mapping = new JSONObjectMapping(nativeType, DefaultMappingFlags, DefaultBindingFlags);
return true;
}
public virtual bool TryGetMapping(Type nativeType,out JSONMapping mapping)
{
if (mappings.TryGetValue(nativeType, out mapping))
return true;
if (RequestCustomMapping(nativeType, out mapping))
return true;
if ((this != DefaultMapper) && DefaultMapper.TryGetMapping(nativeType, out mapping))
return true;
return false;
}
public virtual bool Serialize(object o, out JSONValue json)
{
if (object.ReferenceEquals(null, o))
{
json = JSONNull.Instance;
return true;
}
Type type = o.GetType();
if (RequestCustomSerialization(o, out json))
return true;
if (TryGetMapping(type, out JSONMapping mapping))
{
json = mapping.ToJson(this, o);
return true;
}
if (type.IsEnum)
{
if (type.GetCustomAttribute<FlagsAttribute>() != null)
{
json = new JSONNumber((int)o);
}
else
{
json = new JSONString(Enum.GetName(type, o));
}
return true;
}
if (type.IsPrimitive)
{
throw new NotSupportedException(String.Format("JSONMapperBase: Unsupported primitive type found: {0}", type));
}
if (TryBuildRememberedMapping(type,out mapping))
{
json = mapping.ToJson(this, o);
return true;
}
return false;
}
public virtual bool Deserialize(JSONValue json, Type nativeType, out object o)
{
o = null;
if (JSONNull.Instance.Equals(json))
return true;
if (RequestCustomUnserialization(json, nativeType, out o))
return true;
if (TryGetMapping(nativeType, out JSONMapping mapping))
{
o = mapping.FromJson(this, json);
return true;
}
if (nativeType.IsEnum)
{
if (nativeType.GetCustomAttribute<FlagsAttribute>() != null)
{
o = Enum.ToObject(nativeType, (json as JSONNumber).AsInt);
}
else
{
o = Enum.Parse(nativeType, (json as JSONString).Value);
}
return true;
}
if (nativeType.IsPrimitive)
{
throw new NotSupportedException(string.Format("JSONMapperBase: Unsupported primitive type found: {0}", nativeType));
}
if (TryBuildRememberedMapping(nativeType, out mapping))
{
o = mapping.FromJson(this, json);
return true;
}
return false;
}
public void Apply(string jsonString, object o) => Apply((JSONObject)JSONParser.Parse(jsonString), o);
public virtual bool Apply(JSONObject json, object o)
{
Type nativeType = o.GetType();
if (TryGetMapping(nativeType,out JSONMapping mapping) || TryBuildRememberedMapping(nativeType, out mapping))
{
JSONObjectMapping objectMapping = mapping as JSONObjectMapping;
objectMapping.Apply(json, o);
return true;
}
return false;
}
public virtual JSONValue ToJson(object o)
{
if (Serialize(o,out JSONValue json))
return json;
throw new NotSupportedException();
}
public virtual T FromJson<T>(JSONValue json) => (T)FromJson(json, typeof(T));
public virtual object FromJson(JSONValue json,Type targetType)
{
if (Deserialize(json, targetType, out object o))
return o;
throw new NotSupportedException();
}
static JSONMapper()
{
DefaultMapper.Add(new JSONMapping(
typeof(byte),
(JSONMapper arg1, object arg2) => new JSONNumber((int)arg2),
(JSONMapper arg1, JSONValue arg2) => Decimal.ToByte(((JSONNumber)arg2).Decimal)
));
DefaultMapper.Add(new JSONMapping(
typeof(short),
(JSONMapper arg1, object arg2) => new JSONNumber((int)arg2),
(JSONMapper arg1, JSONValue arg2) => Decimal.ToInt16(((JSONNumber)arg2).Decimal)
));
DefaultMapper.Add(new JSONMapping(
typeof(int),
(JSONMapper arg1, object arg2) => new JSONNumber((int)arg2),
(JSONMapper arg1, JSONValue arg2) => Decimal.ToInt32(((JSONNumber)arg2).Decimal)
));
DefaultMapper.Add(new JSONMapping(
typeof(long),
(JSONMapper arg1, object arg2) => new JSONNumber((long)arg2),
(JSONMapper arg1, JSONValue arg2) => Decimal.ToInt64(((JSONNumber)arg2).Decimal)
));
DefaultMapper.Add(new JSONMapping(
typeof(ushort),
(JSONMapper arg1, object arg2) => new JSONNumber((uint)arg2),
(JSONMapper arg1, JSONValue arg2) => Decimal.ToUInt16(((JSONNumber)arg2).Decimal)
));
DefaultMapper.Add(new JSONMapping(
typeof(uint),
(JSONMapper arg1, object arg2) => new JSONNumber((uint)arg2),
(JSONMapper arg1, JSONValue arg2) => Decimal.ToUInt32(((JSONNumber)arg2).Decimal)
));
DefaultMapper.Add(new JSONMapping(
typeof(ulong),
(JSONMapper arg1, object arg2) => new JSONNumber((ulong)arg2),
(JSONMapper arg1, JSONValue arg2) => Decimal.ToUInt64(((JSONNumber)arg2).Decimal)
));
/**
* Float
**/
DefaultMapper.Add(new JSONMapping(
typeof(float),
(JSONMapper arg1, object arg2) => new JSONNumber((float)arg2),
(JSONMapper arg1, JSONValue arg2) => (float)Decimal.ToDouble(((JSONNumber)arg2).Decimal)
));
DefaultMapper.Add(new JSONMapping(
typeof(double),
(JSONMapper arg1, object arg2) => new JSONNumber((double)arg2),
(JSONMapper arg1, JSONValue arg2) => Decimal.ToDouble(((JSONNumber)arg2).Decimal)
));
/**
* Strings
**/
DefaultMapper.Add(new JSONMapping(
typeof(string),
(JSONMapper arg1, object arg2) => new JSONString((string)arg2),
(JSONMapper arg1, JSONValue arg2) => ((JSONString)arg2).Value
));
/**
* Others
**/
DefaultMapper.Add(new JSONMapping(
typeof(char),
(JSONMapper arg1, object arg2) => new JSONString(new String(new char[] { (char)arg2 })),
(JSONMapper arg1, JSONValue arg2) => ((JSONString)arg2).Value[0]
));
DefaultMapper.Add(new JSONMapping(
typeof(bool),
(JSONMapper arg1, object arg2) => ((bool)arg2) ? (JSONValue)JSONTrue.Instance : (JSONValue)JSONFalse.Instance,
(JSONMapper arg1, JSONValue arg2) => (arg2.ValueType == JSONValueType.TRUE) || (arg2.ValueType == JSONValueType.FALSE) ? false : throw new NotSupportedException()
));
DefaultMapper.Add(new JSONByteArrayMapping());
DefaultMapper.Add(new JSONDateTimeMapping());
DefaultMapper.Add(new JSONDateTimeOffsetMapping());
DefaultMapper.Add(new JSONGuidMapping());
DefaultMapper.Add(new JSONTimeSpanMapping());
DefaultMapper.Add(new JSONRPCCallMapping());
DefaultMapper.Add(new JSONRPCResultMapping());
}
}
}