Support deserializing empty TimeSpan (dotnet/corefx#31750)
authorJiayi Yu <14067510+yujayee@users.noreply.github.com>
Tue, 28 Aug 2018 17:46:09 +0000 (10:46 -0700)
committerGitHub <noreply@github.com>
Tue, 28 Aug 2018 17:46:09 +0000 (10:46 -0700)
* add empty check for timespan
* fix in reflection based and code gen
* add test

Commit migrated from https://github.com/dotnet/corefx/commit/da1089a659b6c16d7dd676a4a806c822351a902a

src/libraries/System.Private.Xml/src/System/Xml/Serialization/PrimitiveXmlSerializers.cs
src/libraries/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationReader.cs
src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReader.cs
src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReaderILGen.cs
src/libraries/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.cs

index b891372..b03d9b7 100644 (file)
@@ -634,6 +634,12 @@ namespace System.Xml.Serialization
             {
                 if (((object)Reader.LocalName == (object)_id19_TimeSpan && (object)Reader.NamespaceURI == (object)_id2_Item))
                 {
+                    if(Reader.IsEmptyElement)
+                    {
+                        Reader.Skip();
+                        o = default(TimeSpan);
+                    }
+                    else
                     {
                         o = System.Xml.XmlConvert.ToTimeSpan(Reader.ReadElementString());
                     }
index bbb478d..fcd2990 100644 (file)
@@ -851,6 +851,11 @@ namespace System.Xml.Serialization
                 {
                     Reader.Skip();
                 }
+                else if(element.Mapping.TypeDesc.Type == typeof(TimeSpan) && Reader.IsEmptyElement)
+                {                   
+                    Reader.Skip();
+                    value = default(TimeSpan);                   
+                }
                 else
                 {
                     if (element.Mapping.TypeDesc == QnameTypeDesc)
index 7edf217..6469ca5 100644 (file)
@@ -4736,27 +4736,50 @@ namespace System.Xml.Serialization
                 }
                 Writer.Indent++;
 
-                WriteSourceBegin(source);
-                if (element.Mapping.TypeDesc == QnameTypeDesc)
-                    Writer.Write("ReadElementQualifiedName()");
+                if (element.Mapping.TypeDesc.Type == typeof(TimeSpan))
+                {
+                    Writer.WriteLine("if (Reader.IsEmptyElement) {");
+                    Writer.Indent++;
+                    Writer.WriteLine("Reader.Skip();");
+                    WriteSourceBegin(source);
+                    Writer.Write("default(System.TimeSpan)");
+                    WriteSourceEnd(source);
+                    Writer.WriteLine(";");
+                    Writer.Indent--;
+                    Writer.WriteLine("}");
+                    Writer.WriteLine("else {");
+                    Writer.Indent++;
+                    WriteSourceBegin(source);
+                    WritePrimitive(element.Mapping, "Reader.ReadElementString()");
+                    WriteSourceEnd(source);
+                    Writer.WriteLine(";");
+                    Writer.Indent--;
+                    Writer.WriteLine("}");
+                }
                 else
                 {
-                    string readFunc;
-                    switch (element.Mapping.TypeDesc.FormatterName)
+                    WriteSourceBegin(source);
+                    if (element.Mapping.TypeDesc == QnameTypeDesc)
+                        Writer.Write("ReadElementQualifiedName()");
+                    else
                     {
-                        case "ByteArrayBase64":
-                        case "ByteArrayHex":
-                            readFunc = "false";
-                            break;
-                        default:
-                            readFunc = "Reader.ReadElementString()";
-                            break;
+                        string readFunc;
+                        switch (element.Mapping.TypeDesc.FormatterName)
+                        {
+                            case "ByteArrayBase64":
+                            case "ByteArrayHex":
+                                readFunc = "false";
+                                break;
+                            default:
+                                readFunc = "Reader.ReadElementString()";
+                                break;
+                        }
+                        WritePrimitive(element.Mapping, readFunc);
                     }
-                    WritePrimitive(element.Mapping, readFunc);
-                }
 
-                WriteSourceEnd(source);
-                Writer.WriteLine(";");
+                    WriteSourceEnd(source);
+                    Writer.WriteLine(";");
+                }
                 Writer.Indent--;
                 Writer.WriteLine("}");
             }
index 5a31494..407080d 100644 (file)
@@ -3045,34 +3045,78 @@ namespace System.Xml.Serialization
                 {
                 }
 
-                WriteSourceBegin(source);
-                if (element.Mapping.TypeDesc == QnameTypeDesc)
+                if (element.Mapping.TypeDesc.Type == typeof(TimeSpan))
                 {
-                    MethodInfo XmlSerializationReader_ReadElementQualifiedName = typeof(XmlSerializationReader).GetMethod(
-                           "ReadElementQualifiedName",
-                           CodeGenerator.InstanceBindingFlags,
-                           Array.Empty<Type>()
-                           );
+                    MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod(
+                       "get_Reader",
+                       CodeGenerator.InstanceBindingFlags,
+                       Array.Empty<Type>()
+                       );
+                    MethodInfo XmlReader_get_IsEmptyElement = typeof(XmlReader).GetMethod(
+                        "get_IsEmptyElement",
+                        CodeGenerator.InstanceBindingFlags,
+                        Array.Empty<Type>()
+                        );
                     ilg.Ldarg(0);
-                    ilg.Call(XmlSerializationReader_ReadElementQualifiedName);
+                    ilg.Call(XmlSerializationReader_get_Reader);
+                    ilg.Call(XmlReader_get_IsEmptyElement);
+                    ilg.If();
+                    WriteSourceBegin(source);
+                    MethodInfo XmlReader_Skip = typeof(XmlReader).GetMethod(
+                        "Skip",
+                        CodeGenerator.InstanceBindingFlags,
+                        Array.Empty<Type>()
+                        );
+                    ilg.Ldarg(0);
+                    ilg.Call(XmlSerializationReader_get_Reader);
+                    ilg.Call(XmlReader_Skip);
+                    ConstructorInfo TimeSpan_ctor = typeof(TimeSpan).GetConstructor(
+                        CodeGenerator.InstanceBindingFlags,
+                        null,
+                        new Type[] { typeof(Int64) },
+                        null
+                        );
+                    ilg.Ldc(default(TimeSpan).Ticks);
+                    ilg.New(TimeSpan_ctor);
+                    WriteSourceEnd(source, element.Mapping.TypeDesc.Type);
+                    ilg.Else();
+                    WriteSourceBegin(source);
+                    WritePrimitive(element.Mapping, "Reader.ReadElementString()");
+                    WriteSourceEnd(source, element.Mapping.TypeDesc.Type);
+                    ilg.EndIf();
                 }
                 else
                 {
-                    string readFunc;
-                    switch (element.Mapping.TypeDesc.FormatterName)
+                    WriteSourceBegin(source);
+                    if (element.Mapping.TypeDesc == QnameTypeDesc)
                     {
-                        case "ByteArrayBase64":
-                        case "ByteArrayHex":
-                            readFunc = "false";
-                            break;
-                        default:
-                            readFunc = "Reader.ReadElementString()";
-                            break;
+                        MethodInfo XmlSerializationReader_ReadElementQualifiedName = typeof(XmlSerializationReader).GetMethod(
+                               "ReadElementQualifiedName",
+                               CodeGenerator.InstanceBindingFlags,
+                               Array.Empty<Type>()
+                               );
+                        ilg.Ldarg(0);
+                        ilg.Call(XmlSerializationReader_ReadElementQualifiedName);
                     }
-                    WritePrimitive(element.Mapping, readFunc);
+                    else
+                    {
+                        string readFunc;
+                        switch (element.Mapping.TypeDesc.FormatterName)
+                        {
+                            case "ByteArrayBase64":
+                            case "ByteArrayHex":
+                                readFunc = "false";
+                                break;
+                            default:
+                                readFunc = "Reader.ReadElementString()";
+                                break;
+                        }
+                        WritePrimitive(element.Mapping, readFunc);
+                    }
+
+                    WriteSourceEnd(source, element.Mapping.TypeDesc.Type);
                 }
 
-                WriteSourceEnd(source, element.Mapping.TypeDesc.Type);
                 if (doEndIf)
                     ilg.EndIf();
             }
index 92fdccd..22f11c3 100644 (file)
@@ -687,6 +687,40 @@ string.Format(@"<?xml version=""1.0"" encoding=""utf-8""?>
     }
 
     [Fact]
+    public static void Xml_DeserializeTypeWithEmptyTimeSpanProperty()
+    {
+        string xml = 
+            @"<?xml version=""1.0""?>
+            <TypeWithTimeSpanProperty xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
+            <TimeSpanProperty />
+            </TypeWithTimeSpanProperty>";
+        XmlSerializer serializer = new XmlSerializer(typeof(TypeWithTimeSpanProperty));
+
+        using (StringReader reader = new StringReader(xml))
+        {
+            TypeWithTimeSpanProperty deserializedObj = (TypeWithTimeSpanProperty)serializer.Deserialize(reader);
+            Assert.NotNull(deserializedObj);
+            Assert.Equal(default(TimeSpan), deserializedObj.TimeSpanProperty);
+        }
+    }
+
+    [Fact]
+    public static void Xml_DeserializeEmptyTimeSpanType()
+    {
+        string xml =
+    @"<?xml version=""1.0""?>
+     <TimeSpan />";
+        XmlSerializer serializer = new XmlSerializer(typeof(TimeSpan));
+
+        using (StringReader reader = new StringReader(xml))
+        {
+            TimeSpan deserializedObj = (TimeSpan)serializer.Deserialize(reader);
+            Assert.NotNull(deserializedObj);
+            Assert.Equal(default(TimeSpan), deserializedObj);
+        }
+    }
+
+    [Fact]
     public static void Xml_TypeWithByteProperty()
     {
         var obj = new TypeWithByteProperty() { ByteProperty = 123 };