Browse Source

IDictionary`2 serialization support was missing in DataContractJsonSerializer.

Fixed bug #685042.
Atsushi Eno 14 years ago
parent
commit
3f0fe0dcde

+ 9 - 6
mcs/class/System.ServiceModel.Web/System.Runtime.Serialization.Json/JsonSerializationReader.cs

@@ -291,8 +291,10 @@ namespace System.Runtime.Serialization.Json
 #else
 				ret = collectionType.IsArray ? ((ArrayList) c).ToArray (elementType) : c;
 #endif
-			} else if (typeof (IDictionary).IsAssignableFrom(collectionType)) {
-				IDictionary id = (IDictionary)Activator.CreateInstance (collectionType);
+			} else if (TypeMap.IsDictionary (collectionType)) {
+				object dic = Activator.CreateInstance (collectionType);
+				var itemSetter = dic.GetType ().GetProperty ("Item");
+				var keyarr = new object [1];
 
 				for (reader.MoveToContent (); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ()) {
 					if (!reader.IsStartElement ("item"))
@@ -301,13 +303,14 @@ namespace System.Runtime.Serialization.Json
 					// reading a KeyValuePair in the form of <Key .../><Value .../>
 					reader.Read ();
 					reader.MoveToContent ();
-					object key = ReadObject (elementType.GetGenericArguments ()[0]);
+					object key = ReadObject (elementType.GetGenericArguments () [0]);
 					reader.MoveToContent ();
-					object val = ReadObject (elementType.GetGenericArguments ()[1]);
+					object val = ReadObject (elementType.GetGenericArguments () [1]);
 					reader.Read ();
-					id[key] = val;
+					keyarr [0] = key;
+					itemSetter.SetValue (dic, val, keyarr);
 				}
-				ret = id;
+				ret = dic;
 			} else {
 				object c = Activator.CreateInstance (collectionType);
 				MethodInfo add = collectionType.GetMethod ("Add", new Type [] {elementType});

+ 8 - 5
mcs/class/System.ServiceModel.Web/System.Runtime.Serialization.Json/JsonSerializationWriter.cs

@@ -114,10 +114,12 @@ namespace System.Runtime.Serialization.Json
 					writer.WriteString (qn.Name);
 					writer.WriteString (":");
 					writer.WriteString (qn.Namespace);
-				} else if (graph is IDictionary) {
+				} else if (TypeMap.IsDictionary (graph.GetType ())) {
 					writer.WriteAttributeString ("type", "array");
-					IDictionary dic = (IDictionary) graph;
-					foreach (object o in dic.Keys) {
+					var itemGetter = graph.GetType ().GetProperty ("Item");
+					var keysGetter = graph.GetType ().GetProperty ("Keys");
+					var argarr = new object [1];
+					foreach (object o in (IEnumerable) keysGetter.GetValue (graph, null)) {
 						writer.WriteStartElement ("item");
 						writer.WriteAttributeString ("type", "object");
 						// outputting a KeyValuePair as <Key .. /><Value ... />
@@ -125,11 +127,12 @@ namespace System.Runtime.Serialization.Json
 						WriteObjectContent (o, false, !(graph is Array && graph.GetType ().GetElementType () != typeof (object)));
 						writer.WriteEndElement ();
 						writer.WriteStartElement ("Value");
-						WriteObjectContent (dic[o], false, !(graph is Array && graph.GetType ().GetElementType () != typeof (object)));
+						argarr [0] = o;
+						WriteObjectContent (itemGetter.GetValue (graph, argarr), false, !(graph is Array && graph.GetType ().GetElementType () != typeof (object)));
 						writer.WriteEndElement ();
 						writer.WriteEndElement ();
 					}
-				} else if (graph is ICollection) { // array
+				} else if (TypeMap.IsCollection (graph.GetType ())) { // array
 					writer.WriteAttributeString ("type", "array");
 					foreach (object o in (ICollection) graph) {
 						writer.WriteStartElement ("item");

+ 11 - 2
mcs/class/System.ServiceModel.Web/System.Runtime.Serialization.Json/TypeMap.cs

@@ -89,13 +89,22 @@ namespace System.Runtime.Serialization.Json
 				if (!fi.IsStatic)
 					l.Add (new TypeMapField (fi, null));
 			foreach (var pi in type.GetProperties ())
-				if (pi.CanRead && pi.CanWrite && !pi.GetGetMethod ().IsStatic)
+				if (pi.CanRead && pi.CanWrite && !pi.GetGetMethod ().IsStatic && pi.GetIndexParameters ().Length == 0)
 					l.Add (new TypeMapProperty (pi, null));
 			l.Sort ((x, y) => x.Order != y.Order ? x.Order - y.Order : String.Compare (x.Name, y.Name, StringComparison.Ordinal));
 			return new TypeMap (type, null, l.ToArray ());
 		}
 
-		static bool IsCollection (Type type)
+		internal static bool IsDictionary (Type type)
+		{
+			if (type.GetInterface ("System.Collections.IDictionary", false) != null)
+				return true;
+			if (type.GetInterface ("System.Collections.Generic.IDictionary`2", false) != null)
+				return true;
+			return false;
+		}
+
+		internal static bool IsCollection (Type type)
 		{
 			if (type.GetInterface ("System.Collections.IList", false) != null)
 				return true;

+ 104 - 0
mcs/class/System.ServiceModel.Web/Test/System.Runtime.Serialization.Json/DataContractJsonSerializerTest.cs

@@ -34,6 +34,7 @@
 //
 
 using System;
+using System.Collections;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.IO;
@@ -1400,6 +1401,23 @@ namespace MonoTests.System.Runtime.Serialization.Json
 				}
 			}
 		}
+
+		[Test]
+		public void DictionarySerialization ()
+		{
+			var dict = new MyDictionary<string,string> ();
+			dict.Add ("key", "value");
+			var serializer = new DataContractJsonSerializer (dict.GetType ());
+			var stream = new MemoryStream ();
+			serializer.WriteObject (stream, dict);
+			stream.Position = 0;
+
+			Assert.AreEqual ("[{\"Key\":\"key\",\"Value\":\"value\"}]", new StreamReader (stream).ReadToEnd (), "#1");
+			stream.Position = 0;
+			dict = (MyDictionary<string,string>) serializer.ReadObject (stream);
+			Assert.AreEqual (1, dict.Count, "#2");
+			Assert.AreEqual ("value", dict ["key"], "#3");
+		}
 	}
 	
 	public class CharTest
@@ -1624,3 +1642,89 @@ class GlobalSample1
 {
 }
 
+
+public class MyDictionary<K, V> : System.Collections.Generic.IDictionary<K, V>
+{
+	Dictionary<K,V> dic = new Dictionary<K,V> ();
+
+	public void Add (K key, V value)
+	{
+		dic.Add (key,  value);
+	}
+
+	public bool ContainsKey (K key)
+	{
+		return dic.ContainsKey (key);
+	}
+
+	public ICollection<K> Keys {
+		get { return dic.Keys; }
+	}
+
+	public bool Remove (K key)
+	{
+		return dic.Remove (key);
+	}
+
+	public bool TryGetValue (K key, out V value)
+	{
+		return dic.TryGetValue (key, out value);
+	}
+
+	public ICollection<V> Values {
+		get { return dic.Values; }
+	}
+
+	public V this [K key] {
+		get { return dic [key]; }
+		set { dic [key] = value; }
+	}
+
+	IEnumerator IEnumerable.GetEnumerator ()
+	{
+		return dic.GetEnumerator ();
+	}
+
+	ICollection<KeyValuePair<K,V>> Coll {
+		get { return (ICollection<KeyValuePair<K,V>>) dic; }
+	}
+
+	public void Add (KeyValuePair<K, V> item)
+	{
+		Coll.Add (item);
+	}
+
+	public void Clear ()
+	{
+		dic.Clear ();
+	}
+
+	public bool Contains (KeyValuePair<K, V> item)
+	{
+		return Coll.Contains (item);
+	}
+
+	public void CopyTo (KeyValuePair<K, V> [] array, int arrayIndex)
+	{
+		Coll.CopyTo (array, arrayIndex);
+	}
+
+	public int Count {
+		get { return dic.Count; }
+	}
+
+	public bool IsReadOnly {
+		get { return Coll.IsReadOnly; }
+	}
+
+	public bool Remove (KeyValuePair<K, V> item)
+	{
+		return Coll.Remove (item);
+	}
+
+	public IEnumerator<KeyValuePair<K, V>> GetEnumerator ()
+	{
+		return Coll.GetEnumerator ();
+	}
+}
+