XmlSerializer: Add support to serialize nullable types when the XmlElement has explic...
authorMiguel de Icaza <miguel@gnome.org>
Wed, 4 Jan 2012 00:38:01 +0000 (19:38 -0500)
committerMiguel de Icaza <miguel@gnome.org>
Wed, 4 Jan 2012 00:38:13 +0000 (19:38 -0500)
The existing code had a special code path for handling nullables that
ignored the DataType component.

This patch splits the nullable test away, allows the specified XmlDataType
to be probed and then performs the standard type lookup mechanism.

This allows this:

        [XmlElement ("MyNullableTime", DataType="time", IsNullable=true)]
        DateTime? myTime;

To be serialized as a "time" instead of a "datetime".

Fixes bug #329

mcs/class/System.XML/System.Xml.Serialization/TypeTranslator.cs
mcs/class/System.XML/Test/System.Xml.Serialization/XmlSerializationWriterTests.cs
mcs/class/System.XML/Test/System.Xml.Serialization/XmlSerializerTestClasses.cs

index 745387feef187f4832f3aff2d330dd5d0e36a975..68afc6e9a87233a13e6a230793225605db596d70 100644 (file)
@@ -176,27 +176,8 @@ namespace System.Xml.Serialization
                        if (type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>)) {
                                nullableOverride = true;
                                type = type.GetGenericArguments () [0];
-
-                               TypeData pt = GetTypeData (type); // beware this recursive call btw ...
-                               if (pt != null) {
-                                               TypeData tt = (TypeData) nullableTypes [pt.XmlType];
-#if TARGET_JVM
-                                               if (tt == null)
-                                                       tt = (TypeData) AppDomain_nullableTypes [pt.XmlType];
-#endif
-                                               if (tt == null) {
-                                                       tt = new TypeData (type, pt.XmlType, false);
-                                                       tt.IsNullable = true;
-#if TARGET_JVM
-                                                       AppDomain_nullableTypes [pt.XmlType] = tt;
-#else
-                                                       nullableTypes [pt.XmlType] = tt;
-#endif
-                                               }
-                                               return tt;
-                               }
                        }
-#endif
+
 
                        if ((xmlDataType != null) && (xmlDataType.Length != 0)) {
                                // If the type is an array, xmlDataType specifies the type for the array elements,
@@ -215,9 +196,40 @@ namespace System.Xml.Serialization
                                                else
                                                        throw new InvalidOperationException ("Cannot convert values of type '" + type.GetElementType () + "' to '" + xmlDataType + "'");
                                }
+                               if (nullableOverride){
+                                       TypeData tt = (TypeData) nullableTypes [at.XmlType];
+                                       if (tt == null){
+                                               tt = new TypeData (type, at.XmlType, false);
+                                               tt.IsNullable = true;
+                                               nullableTypes [at.XmlType] = tt;
+                                       }
+                                       return tt;
+                               }
                                return at;
                        }
 
+                       if (nullableOverride){
+                               TypeData pt = GetTypeData (type); // beware this recursive call btw ...
+                               if (pt != null) {
+                                               TypeData tt = (TypeData) nullableTypes [pt.XmlType];
+#if TARGET_JVM
+                                               if (tt == null)
+                                                       tt = (TypeData) AppDomain_nullableTypes [pt.XmlType];
+#endif
+                                               if (tt == null) {
+                                                       tt = new TypeData (type, pt.XmlType, false);
+                                                       tt.IsNullable = true;
+#if TARGET_JVM
+                                                       AppDomain_nullableTypes [pt.XmlType] = tt;
+#else
+                                                       nullableTypes [pt.XmlType] = tt;
+#endif
+                                               }
+                                               return tt;
+                               }
+                       }
+#endif
+                       
                                TypeData typeData = nameCache[runtimeType] as TypeData;
                                if (typeData != null) return typeData;
 
index c86b727874f918f4e4b513448a43ca0798706b06..f58d0e35884e0680217fc3947d6c9cb8ad2356e8 100644 (file)
@@ -4,6 +4,8 @@
 // Author: Erik LeBel <eriklebel@yahoo.ca>
 //
 //  (C) Erik LeBel 2003
+// Copyright 2003-2011 Novell 
+// Copyright 2011 Xamarin Inc
 //  
 // FIXME add tests for callbacks
 // FIXME add tests for writes that generate namespaces
@@ -1582,5 +1584,30 @@ namespace MonoTests.System.XmlSerialization
                        [DefaultValue ('a')]
                        public char character = '\'';
                }
+
+               [Test]
+               public void TestNullableDatesAndTimes ()
+               {
+                       DateTime dt = new DateTime (2012, 1, 3, 10, 0, 0, 0);
+                       
+                       var d = new NullableDatesAndTimes () {
+                               MyTime = dt,
+                               MyTimeNullable = dt,
+                               MyDate = dt,
+                               MyDateNullable = dt
+                       };
+                       
+                       XmlSerializer ser = new XmlSerializer (d.GetType ());
+                       StringWriter sw = new StringWriter ();
+                       ser.Serialize (sw, d);
+                       string str = sw.ToString ();
+
+                       Assert.IsTrue (str.IndexOf ("<MyTime>10:00:00</MyTime>") != -1, "Time");
+                       Assert.IsTrue (str.IndexOf ("<MyTimeNullable>10:00:00</MyTimeNullable>") != -1, "Nullable Time");
+                       Assert.IsTrue (str.IndexOf ("<MyDate>2012-01-03</MyDate>") != -1, "Date");
+                       Assert.IsTrue (str.IndexOf ("<MyDateNullable>2012-01-03</MyDateNullable>") != -1, "Nullable Datwe");
+               }
+               
+               
        }
 }
index f478076c4fe18a8387201f5aec6b72ee085ef071..8d6af186a7f563161a031678dc9c65b3da2caa68 100644 (file)
@@ -1032,5 +1032,20 @@ namespace MonoTests.System.Xml.TestClasses
                [XmlAttribute]
                public string Child3;
        }
+
+       [XmlRoot ("root")]
+       public class NullableDatesAndTimes {
+               [XmlElementAttribute ("MyTime", DataType = "time", IsNullable = false)]
+               public DateTime MyTime;
+                       
+               [XmlElementAttribute ("MyTimeNullable", DataType = "time", IsNullable = true)]
+               public DateTime? MyTimeNullable;
+               
+               [XmlElementAttribute ("MyDate", DataType = "date", IsNullable = false)]
+               public DateTime MyDate;
+               
+               [XmlElementAttribute ("MyDateNullable", DataType = "date", IsNullable = true)]
+               public DateTime? MyDateNullable;
+       }
 }