Implement support for KnownTypeAttribute.MethodName.
authorAtsushi Eno <atsushi@ximian.com>
Fri, 15 Apr 2011 06:40:42 +0000 (15:40 +0900)
committerAtsushi Eno <atsushi@ximian.com>
Fri, 15 Apr 2011 06:40:42 +0000 (15:40 +0900)
mcs/class/System.Runtime.Serialization/System.Runtime.Serialization/DataContractSerializer.cs
mcs/class/System.Runtime.Serialization/System.Runtime.Serialization/KnownTypeAttribute.cs
mcs/class/System.Runtime.Serialization/System.Runtime.Serialization/KnownTypeCollection.cs
mcs/class/System.Runtime.Serialization/System.Runtime.Serialization_test.dll.sources
mcs/class/System.Runtime.Serialization/Test/System.Runtime.Serialization/KnownTypeAttributeTest.cs [new file with mode: 0644]

index 3cfe9d5515601b5e279495e0b6131b877f85f1c2..b7454db9812769e1dcc0579c0ce6363f4a2a80ed 100755 (executable)
@@ -231,7 +231,8 @@ namespace System.Runtime.Serialization
                        object [] attrs = elementType.GetCustomAttributes (typeof (KnownTypeAttribute), true);
                        for (int i = 0; i < attrs.Length; i ++) {
                                KnownTypeAttribute kt = (KnownTypeAttribute) attrs [i];
-                               known_types.Add (kt.Type);
+                               foreach (var t in kt.GetTypes (elementType))
+                                       known_types.Add (t);
                        }
                }
 
index 8f17d01ff38265bec97189deb911f9a3b81b9540..3e225f9cdc67b7c236f240a4cf608a2493092136 100644 (file)
@@ -27,6 +27,8 @@
 //
 #if NET_2_0
 using System;
+using System.Collections.Generic;
+using System.Reflection;
 
 namespace System.Runtime.Serialization
 {
@@ -39,11 +41,15 @@ namespace System.Runtime.Serialization
 
                public KnownTypeAttribute (string methodName)
                {
+                       if (methodName == null)
+                               throw new ArgumentNullException ("methodName");
                        method_name = methodName;
                }
 
                public KnownTypeAttribute (Type type)
                {
+                       if (type == null)
+                               throw new ArgumentNullException ("type");
                        this.type = type;
                }
 
@@ -54,6 +60,26 @@ namespace System.Runtime.Serialization
                public Type Type {
                        get { return type; }
                }
+
+               MethodInfo method_cache;
+
+               internal IEnumerable<Type> GetTypes (Type type)
+               {
+                       if (method_cache != null)
+                               return (IEnumerable<Type>) method_cache.Invoke (null, new object [0]);
+
+                       if (Type != null)
+                               return new Type [] {Type};
+                       else {
+                               var mi = type.GetMethod (MethodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static, null, Type.EmptyTypes, null);
+                               if (mi == null)
+                                       throw new InvalidDataContractException (String.Format ("KnownTypeAttribute on {0} specifies '{1}' method, but that does not exist. The methos must be static.", type, MethodName));
+                               if (!typeof (IEnumerable<Type>).IsAssignableFrom (mi.ReturnType))
+                                       throw new InvalidDataContractException (String.Format ("KnownTypeAttribute on {0} specifies '{1}' method, but it returns {2} which cannot be assignable from IEnumerable<Type>.", type, MethodName, mi.ReturnType));
+                               method_cache = mi;
+                               return GetTypes (type);
+                       }
+               }
        }
 }
 #endif
index 15db798b0967747c1fcaf88c7ca25adfa08e470a..7c6472cb83d15dca12379b40689e901f4b545e2b 100755 (executable)
@@ -869,7 +869,8 @@ namespace System.Runtime.Serialization
                        object [] attrs = type.GetCustomAttributes (typeof (KnownTypeAttribute), true);
                        for (int i = 0; i < attrs.Length; i++) {
                                KnownTypeAttribute kt = (KnownTypeAttribute) attrs [i];
-                               TryRegister (kt.Type);
+                               foreach (var t in kt.GetTypes (type))
+                                       TryRegister (t);
                        }
 
                        return ret;
index 978b301ace162b0d5af64f4f014778c13d7e9d20..12ff752a9c6913c04b63e53c47a9dc7a2495fb02 100644 (file)
@@ -1,6 +1,7 @@
 System.Runtime.Serialization/Bug666333Test.cs
 System.Runtime.Serialization/Bug675144Test.cs
 System.Runtime.Serialization/DataContractResolverTest.cs
+System.Runtime.Serialization/KnownTypeAttributeTest.cs
 System.Runtime.Serialization/XmlObjectSerializerTest.cs
 System.Runtime.Serialization/XsdDataContractExporterTest.cs
 System.Runtime.Serialization/XsdDataContractImporterTest.cs
diff --git a/mcs/class/System.Runtime.Serialization/Test/System.Runtime.Serialization/KnownTypeAttributeTest.cs b/mcs/class/System.Runtime.Serialization/Test/System.Runtime.Serialization/KnownTypeAttributeTest.cs
new file mode 100644 (file)
index 0000000..f529095
--- /dev/null
@@ -0,0 +1,139 @@
+//
+// Author:
+//     Atsushi Enomoto <atsushi@ximian.com>
+//
+// Copyright (C) 2011 Novell, Inc.  http://www.novell.com
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#if NET_2_0
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Runtime.Serialization;
+using System.Xml;
+using NUnit.Framework;
+
+namespace MonoTests.System.Runtime.Serialization
+{
+       [TestFixture]
+       public class KnownTypeAttributeTest
+       {
+               void Serialize (object instance)
+               {
+                       var ds = new DataContractSerializer (instance.GetType ());
+                       using (var xw = XmlWriter.Create (TextWriter.Null))
+                               ds.WriteObject (xw, instance);
+               }
+
+               [Test]
+               public void MethodName ()
+               {
+                       Serialize (new Data () { X = new Bar () });
+               }
+
+               [Test]
+               public void MethodName2 ()
+               {
+                       Serialize (new Data2 () { X = new Bar () });
+               }
+
+               [Test]
+               [ExpectedException (typeof (InvalidDataContractException))]
+               public void MethodName3 ()
+               {
+                       Serialize (new Data3 () { X = new Bar () });
+               }
+
+               [Test]
+               [ExpectedException (typeof (InvalidDataContractException))]
+               public void MethodName4 ()
+               {
+                       Serialize (new Data4 () { X = new Bar () });
+               }
+
+               public class Foo
+               {
+                       public string S { get; set; }
+               }
+
+               public class Bar : Foo
+               {
+                       public string T { get; set; }
+               }
+
+               [DataContract]
+               [KnownType ("GetTypes")]
+               public class Data
+               {
+                       [DataMember]
+                       public Foo X { get; set; }
+
+                       public static IEnumerable<Type> GetTypes ()
+                       {
+                               yield return typeof (Bar);
+                       }
+               }
+
+               [DataContract]
+               [KnownType ("GetTypes")]
+               public class Data2
+               {
+                       [DataMember]
+                       public Foo X { get; set; }
+
+                       static IEnumerable<Type> GetTypes () // non-public
+                       {
+                               yield return typeof (Bar);
+                       }
+               }
+
+               [DataContract]
+               [KnownType ("GetTypes")]
+               public class Data3
+               {
+                       [DataMember]
+                       public Foo X { get; set; }
+
+                       public IEnumerable<Type> GetTypes () // non-static
+                       {
+                               yield return typeof (Bar);
+                       }
+               }
+
+               [DataContract]
+               [KnownType ("GetTypes")]
+               public class Data4
+               {
+                       [DataMember]
+                       public Foo X { get; set; }
+
+                       public static IEnumerable<Type> GetTypes (ICustomAttributeProvider provider) // wrong args
+                       {
+                               yield return typeof (Bar);
+                       }
+               }
+       }
+}
+#endif