From 06ba17a22c025fb9ff6ed558ede7075205921278 Mon Sep 17 00:00:00 2001 From: KaiLin Ge Date: Thu, 1 Feb 2018 00:55:40 +0800 Subject: [PATCH] better custom type, fix List & Dictionary deserialization --- UnitTests/Tests.cs | 78 +++++++++++++++++++++++++++++++------- fastJSON/JSON.cs | 38 +++++++++++++------ fastJSON/JsonSerializer.cs | 7 +++- fastJSON/Reflection.cs | 4 +- 4 files changed, 100 insertions(+), 27 deletions(-) diff --git a/UnitTests/Tests.cs b/UnitTests/Tests.cs index 1905dbe..8c40542 100644 --- a/UnitTests/Tests.cs +++ b/UnitTests/Tests.cs @@ -291,7 +291,7 @@ public class RetNestedclass #endregion - [TestFixtureSetUp] + [OneTimeSetUp] public static void setup() { //fastJSON.JSON.Parameters = new JSONParameters(); @@ -1864,24 +1864,76 @@ public static void comments() Assert.AreEqual(2, (o as IDictionary).Count); } - public class ctype + public struct Point { - public System.Net.IPAddress ip; + public int x; + public float y; + } + public class Complex + { + public int i; + public List l; } [Test] public static void CustomTypes() { - var ip = new ctype(); - ip.ip = System.Net.IPAddress.Loopback; - - JSON.RegisterCustomType(typeof(System.Net.IPAddress), - (x) => { return x.ToString(); }, - (x) => { return System.Net.IPAddress.Parse(x); }); - - var s = JSON.ToJSON(ip); + JSON.RegisterCustomType(typeof(Point), + (o) => { + var pt = (Point)o; + return string.Format("[{0},{1}]", pt.x, pt.y); + }, + (o, cb) => { + var l = o as List; + return new Point() { x = Convert.ToInt32(l[0]), y = Convert.ToSingle(l[1]) }; + }); + JSON.RegisterCustomType(typeof(Complex), + (o) => { + var c = (Complex)o; + return string.Format("[{0},{1}]", c.i, JSON.ToJSON(c.l)); + }, + (o, cb) => { + var l = o as List; + return new Complex() { i = Convert.ToInt32(l[0]), l = (List)cb(l[1], typeof(List)) }; + }); - var o = JSON.ToObject(s); - Assert.AreEqual(ip.ip, o.ip); + var pt1 = new Point() { x = 1, y = 2.3f }; + var s = JSON.ToJSON(pt1); + Console.WriteLine(s); + var pt2 = JSON.ToObject(s); + Assert.AreEqual(pt1, pt2); + + var c1 = new Complex() { + i = 9, + l = new List() { + new Point[] { + new Point() { x = 1, y = 2.3f }, + new Point() { x = 2, y = 3.4f }, + }, + new Point[] { + new Point() { x = 5, y = 6.7f }, + }, + } + }; + s = JSON.ToJSON(c1); + Console.WriteLine(s); + var c2 = JSON.ToObject(s); + Assert.AreEqual(s, JSON.ToJSON(c2)); + + var d1 = new Dictionary>>() { + {"a", new List> { + new List { + new Point() { x = 1, y = 2.3f }, + new Point() { x = 2, y = 3.4f }, + }, + new List { + new Point() { x = 5, y = 6.7f }, + }, + }} + }; + s = JSON.ToJSON(d1); + Console.WriteLine(s); + var d2 = JSON.ToObject(s, d1.GetType()); + Assert.AreEqual(s, JSON.ToJSON(d2)); } [Test] diff --git a/fastJSON/JSON.cs b/fastJSON/JSON.cs index fc2434c..8cd3157 100644 --- a/fastJSON/JSON.cs +++ b/fastJSON/JSON.cs @@ -10,8 +10,9 @@ namespace fastJSON { + public delegate object DeserializeCallback(object data, Type type); public delegate string Serialize(object data); - public delegate object Deserialize(string data); + public delegate object Deserialize(object data, DeserializeCallback cb); public sealed class JSONParameters { @@ -382,6 +383,12 @@ public object ToObject(string json) } public object ToObject(string json, Type type) + { + object o = new JsonParser(json).Decode(); + return ToTyped(o, type); + } + + public object ToTyped(object o, Type type) { //_params = Parameters; _params.FixValues(); @@ -392,7 +399,9 @@ public object ToObject(string json, Type type) _params.UsingGlobalTypes = false; _usingglobals = _params.UsingGlobalTypes; - object o = new JsonParser(json).Decode(); + if ((type != null) && Reflection.Instance.IsTypeRegistered(type)) + return Reflection.Instance.CreateCustom(o, type, ToTyped); + if (o == null) return null; #if !SILVERLIGHT @@ -490,9 +499,6 @@ private object ChangeType(object value, Type conversionType) else if (conversionType == typeof(DateTimeOffset)) return CreateDateTimeOffset((string)value); - else if (Reflection.Instance.IsTypeRegistered(conversionType)) - return Reflection.Instance.CreateCustom((string)value, conversionType); - // 8-30-2014 - James Brooks - Added code for nullable types. if (IsNullable(conversionType)) { @@ -612,8 +618,17 @@ private void DoParseList(object parse, Type it, IList o) { _usingglobals = false; object v = k; - if (k is Dictionary) + if ((it != null) && Reflection.Instance.IsTypeRegistered(it)) + v = Reflection.Instance.CreateCustom(k, it, ToTyped); + else if (k is Dictionary) v = ParseDictionary(k as Dictionary, globals, it, null); + else if (k is List) + { + if (it != null && it.IsArray) + v = RootArray(k, it); + else + v = RootList(k, it); + } else v = ChangeType(k, it); @@ -682,6 +697,8 @@ internal object ParseDictionary(Dictionary d, Dictionary))) + return RootDictionary(d, type); if (d.TryGetValue("$i", out tn)) { @@ -789,7 +806,7 @@ internal object ParseDictionary(Dictionary d, Dictionary)v, pi.pt, pi.GenericTypes, globaltypes); break; case myPropInfoType.NameValue: oset = CreateNV((Dictionary)v); break; case myPropInfoType.StringDictionary: oset = CreateSD((Dictionary)v); break; - case myPropInfoType.Custom: oset = Reflection.Instance.CreateCustom((string)v, pi.pt); break; + case myPropInfoType.Custom: oset = Reflection.Instance.CreateCustom(v, pi.pt, ToTyped); break; default: { if (pi.IsGenericType && pi.IsValueType == false && v is List) @@ -997,13 +1014,12 @@ private object CreateGenericList(List data, Type pt, Type bt, Dictionary { if (ob is IDictionary) col.Add(ParseDictionary((Dictionary)ob, globalTypes, it, null)); - else if (ob is List) { - if (bt.IsGenericType) - col.Add((List)ob);//).ToArray()); + if (it.IsArray) + col.Add(RootArray(ob, it)); else - col.Add(((List)ob).ToArray()); + col.Add(RootList(ob, it)); } else col.Add(ChangeType(ob, it)); diff --git a/fastJSON/JsonSerializer.cs b/fastJSON/JsonSerializer.cs index 8aaebf8..9db0963 100644 --- a/fastJSON/JsonSerializer.cs +++ b/fastJSON/JsonSerializer.cs @@ -238,7 +238,7 @@ private void WriteCustom(object obj) { Serialize s; Reflection.Instance._customSerializer.TryGetValue(obj.GetType(), out s); - WriteStringFast(s(obj)); + WriteRaw(s(obj)); } private void WriteEnum(Enum e) @@ -686,5 +686,10 @@ private void WriteString(string s) _output.Append('\"'); } + + private void WriteRaw(string s) + { + _output.Append(s); + } } } diff --git a/fastJSON/Reflection.cs b/fastJSON/Reflection.cs index 42aac40..653b2dc 100644 --- a/fastJSON/Reflection.cs +++ b/fastJSON/Reflection.cs @@ -103,11 +103,11 @@ private Reflection() internal SafeDictionary _customSerializer = new SafeDictionary(); internal SafeDictionary _customDeserializer = new SafeDictionary(); - internal object CreateCustom(string v, Type type) + internal object CreateCustom(object v, Type type, DeserializeCallback cb) { Deserialize d; _customDeserializer.TryGetValue(type, out d); - return d(v); + return d(v, cb); } internal void RegisterCustomType(Type type, Serialize serializer, Deserialize deserializer)