Extend JsonSerializerReader to support nullables and parse a wider range of Date...
authorMiguel de Icaza <miguel@gnome.org>
Thu, 24 Nov 2011 06:29:20 +0000 (01:29 -0500)
committerMiguel de Icaza <miguel@gnome.org>
Thu, 24 Nov 2011 06:29:27 +0000 (01:29 -0500)
mcs/class/System.ServiceModel.Web/System.Runtime.Serialization.Json/JsonSerializationReader.cs
mcs/class/System.ServiceModel.Web/Test/System.Runtime.Serialization.Json/DataContractJsonSerializerTest.cs

index 9daa8820181775e06aeebd5c32dda5b8ee609e25..3a5e57ff125906bcbbb5e7a3c1ba5b19600396be 100644 (file)
@@ -72,6 +72,9 @@ namespace System.Runtime.Serialization.Json
                        if (serialized_object_count ++ == serializer.MaxItemsInObjectGraph)
                                throw SerializationError (String.Format ("The object graph exceeded the maximum object count '{0}' specified in the serializer", serializer.MaxItemsInObjectGraph));
 
+                       if (type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>))
+                               type = Nullable.GetUnderlyingType (type);
+                       
                        bool isNull = reader.GetAttribute ("type") == "null";
 
                        switch (Type.GetTypeCode (type)) {
@@ -121,7 +124,29 @@ namespace System.Runtime.Serialization.Json
                                var s = reader.ReadElementContentAsString ();
                                if (s.Length < 2 || !s.StartsWith ("/Date(", StringComparison.Ordinal) || !s.EndsWith (")/", StringComparison.Ordinal))
                                        throw new XmlException ("Invalid JSON DateTime format. The value format should be '/Date(UnixTime)/'");
-                               return new DateTime (1970, 1, 1).AddMilliseconds (long.Parse (s.Substring (6, s.Length - 8)));
+
+                               // The date can contain [SIGN]LONG, [SIGN]LONG+HOURSMINUTES or [SIGN]LONG-HOURSMINUTES
+                               // the format for HOURSMINUTES is DDDD
+                               int tidx = s.IndexOf ('-', 8);
+                               if (tidx == -1)
+                                       tidx = s.IndexOf ('+', 8);
+                               int minutes = 0;
+                               if (tidx == -1){
+                                       s = s.Substring (6, s.Length - 8);
+                               } else {
+                                       int offset;
+                                       int.TryParse (s.Substring (tidx+1, s.Length-3-tidx), out offset);
+
+                                       minutes = (offset % 100) + (offset / 100) * 60;
+                                       if (s [tidx] == '-')
+                                               minutes = -minutes;
+
+                                       s = s.Substring (6, tidx-6);
+                               }
+                               var date = new DateTime (1970, 1, 1).AddMilliseconds (long.Parse (s));
+                               if (minutes != 0)
+                                       date = date.AddMinutes (minutes);
+                               return date;
                        default:
                                if (type == typeof (Guid)) {
                                        return new Guid (reader.ReadElementContentAsString ());
index 3debe78edb1a3662293be5c3ea7014cff279c2e0..2a75876fd0d5f8ce54c51d3b260a8a6edcb44c9d 100644 (file)
@@ -1362,6 +1362,29 @@ namespace MonoTests.System.Runtime.Serialization.Json
                        Assert.AreEqual (query.StartDate, q.StartDate, "#2");
                        Assert.AreEqual (query.EndDate, q.EndDate, "#3");
                }
+
+               [DataContract(Name = "DateTest")]
+               public class DateTest
+               {
+                       [DataMember(Name = "should_have_value")]
+                       public DateTime? ShouldHaveValue { get; set; }
+               }
+
+               //
+               // This tests both the extended format "number-0500" as well
+               // as the nullable field in the structure
+               [Test]
+               public void BugXamarin163 ()
+               {
+                       string json = @"{""should_have_value"":""\/Date(1277355600000-0500)\/""}";
+
+                       byte[] bytes = global::System.Text.Encoding.UTF8.GetBytes(json);
+                       Stream inputStream = new MemoryStream(bytes);
+                       
+                       DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(DateTest));
+                       DateTest t = serializer.ReadObject(inputStream) as DateTest;
+                       Assert.AreEqual (634129344000000000, t.ShouldHaveValue.Value.Ticks, "#1");
+               }
                
                [Test]
                public void DeserializeNullMember ()