Use SortedDictionary in System.Json.JsonObject
authorSteffen Kieß <Steffen.Kiess@ipvs.uni-stuttgart.de>
Fri, 11 Jul 2014 14:04:42 +0000 (16:04 +0200)
committerSteffen Kieß <Steffen.Kiess@ipvs.uni-stuttgart.de>
Fri, 11 Jul 2014 14:13:41 +0000 (16:13 +0200)
Currently JsonObject uses a Dictionary and JsonValue does not sort the keys
in SaveInternal(). As iterating over a Dictionary returns the values in
random order, this causes the JSON string to be non-deterministic.
Switching to SortedDictionary makes sure that the same object always will
produce the same JSON string.
The keys are sorted using StringComparer.Ordinal to produce the same order
in all locales.

mcs/class/System.Json/System.Json/JsonObject.cs
mcs/class/System.Json/Test/System.Json/JsonValueTest.cs

index 33177b1c5f203b40e594f29d120e817057def312..91366a2243a766eac337d7bc7739dfa3df5035be 100644 (file)
@@ -12,11 +12,12 @@ namespace System.Json
 {
        public class JsonObject : JsonValue, IDictionary<string, JsonValue>, ICollection<JsonPair>
        {
-               Dictionary<string, JsonValue> map;
+               // Use SortedDictionary to make result of ToString() deterministic
+               SortedDictionary<string, JsonValue> map;
 
                public JsonObject (params JsonPair [] items)
                {
-                       map = new Dictionary<string, JsonValue> ();
+                       map = new SortedDictionary<string, JsonValue> (StringComparer.Ordinal);
 
                        if (items != null)
                                AddRange (items);
@@ -27,7 +28,7 @@ namespace System.Json
                        if (items == null)
                                throw new ArgumentNullException ("items");
 
-                       map = new Dictionary<string, JsonValue> ();
+                       map = new SortedDictionary<string, JsonValue> (StringComparer.Ordinal);
                        AddRange (items);
                }
 
index bc04e2d403fd3ecd7a985b3259664f569440aa7d..15d5bd82b38de9de751f540c33252eb668d8c7fd 100644 (file)
@@ -46,6 +46,26 @@ namespace MonoTests.System
                        Assert.AreEqual (str, "[1, 2, 3, null]");
                }
 
+               // Test that we correctly serialize JsonObject with null elements.
+               [Test]
+               public void ToStringOnJsonObjectWithNulls () {
+                       var j = JsonValue.Load (new StringReader ("{\"a\":null,\"b\":2}"));
+                       Assert.AreEqual (2, j.Count, "itemcount");
+                       Assert.AreEqual (JsonType.Object, j.JsonType, "type");
+                       var str = j.ToString ();
+                       Assert.AreEqual (str, "{\"a\": null, \"b\": 2}");
+               }
+
+               [Test]
+               public void JsonObjectOrder () {
+                       var obj = new JsonObject ();
+                       obj["a"] = 1;
+                       obj["c"] = 3;
+                       obj["b"] = 2;
+                       var str = obj.ToString ();
+                       Assert.AreEqual (str, "{\"a\": 1, \"b\": 2, \"c\": 3}");
+               }
+
                [Test]
                public void QuoteEscapeBug_20869 () 
                {