Merge pull request #856 from madewokherd/textcontrol
[mono.git] / mcs / class / System.ServiceModel.Web / System.Runtime.Serialization.Json / TypeMap.cs
index ff86987d7eb1e885ec431b562603478bdd68e3c1..3f1cbb510c987815b781679013b22c6f3b0ef360 100644 (file)
@@ -31,7 +31,10 @@ using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Globalization;
 using System.IO;
+using System.Linq;
 using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.Serialization;
 using System.Text;
 using System.Xml;
 
@@ -80,20 +83,29 @@ namespace System.Runtime.Serialization.Json
                {
                        var l = new List<TypeMapMember> ();
                        foreach (var fi in type.GetFields ())
-                               l.Add (new TypeMapField (fi, null));
+                               if (!fi.IsStatic)
+                                       l.Add (new TypeMapField (fi, null));
                        foreach (var pi in type.GetProperties ())
-                               if (pi.CanRead && pi.CanWrite)
+                               if (pi.CanRead && pi.CanWrite && !pi.GetGetMethod (true).IsStatic && pi.GetIndexParameters ().Length == 0)
                                        l.Add (new TypeMapProperty (pi, null));
+                       l.Sort ((x, y) => x.Order != y.Order ? x.Order - y.Order : String.Compare (x.Name, y.Name, StringComparison.Ordinal));
                        return new TypeMap (type, null, l.ToArray ());
                }
 
-               static bool IsCollection (Type type)
+               internal static bool IsDictionary (Type type)
                {
-                       if (type.GetInterface ("System.Collections.IList") != null)
+                       if (type.GetInterface ("System.Collections.IDictionary", false) != null)
                                return true;
-                       if (type.GetInterface ("System.Collections.Generic.IList`1") != null)
+                       if (type.GetInterface ("System.Collections.Generic.IDictionary`2", false) != null)
                                return true;
-                       if (type.GetInterface ("System.Collections.Generic.ICollection`1") != null)
+                       return false;
+               }
+
+               internal static bool IsCollection (Type type)
+               {
+                       if (IsPrimitiveType (type) || IsDictionary (type))
+                               return false;
+                       if (type.GetInterface ("System.Collections.IEnumerable", false) != null)
                                return true;
                        return false;
                }
@@ -105,7 +117,9 @@ namespace System.Runtime.Serialization.Json
 
                        List<TypeMapMember> members = new List<TypeMapMember> ();
 
-                       foreach (FieldInfo fi in type.GetFields (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) {
+                       foreach (FieldInfo fi in type.GetFields (binding_flags)) {
+                               if (fi.GetCustomAttributes (typeof (CompilerGeneratedAttribute), false).Length > 0)
+                                       continue;
                                if (dca != null) {
                                        object [] atts = fi.GetCustomAttributes (typeof (DataMemberAttribute), true);
                                        if (atts.Length == 0)
@@ -113,14 +127,17 @@ namespace System.Runtime.Serialization.Json
                                        DataMemberAttribute dma = (DataMemberAttribute) atts [0];
                                        members.Add (new TypeMapField (fi, dma));
                                } else {
-                                       if (fi.GetCustomAttributes (typeof (NonSerializedAttribute), false).Length > 0)
+                                       if (fi.GetCustomAttributes (typeof (IgnoreDataMemberAttribute), false).Length > 0)
                                                continue;
                                        members.Add (new TypeMapField (fi, null));
                                }
                        }
 
                        if (dca != null) {
-                               foreach (PropertyInfo pi in type.GetProperties (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) {
+                               foreach (PropertyInfo pi in type.GetProperties (binding_flags)) {
+                                       object [] atts = pi.GetCustomAttributes (typeof (DataMemberAttribute), true);
+                                       if (atts.Length == 0)
+                                               continue;
                                        if (pi.GetIndexParameters ().Length > 0)
                                                continue;
                                        if (IsCollection (pi.PropertyType)) {
@@ -129,15 +146,12 @@ namespace System.Runtime.Serialization.Json
                                        }
                                        else if (!pi.CanRead || !pi.CanWrite)
                                                throw new InvalidDataContractException (String.Format ("Non-collection property {0} must have both getter and setter", pi));
-                                       object [] atts = pi.GetCustomAttributes (typeof (DataMemberAttribute), true);
-                                       if (atts.Length == 0)
-                                               continue;
                                        DataMemberAttribute dma = (DataMemberAttribute) atts [0];
                                        members.Add (new TypeMapProperty (pi, dma));
                                }
                        }
 
-                       members.Sort (delegate (TypeMapMember m1, TypeMapMember m2) { return m1.Order - m2.Order; });
+                       members.Sort (delegate (TypeMapMember m1, TypeMapMember m2) { return m1.Order != m2.Order ? m1.Order - m2.Order : String.CompareOrdinal (m1.Name, m2.Name); });
                        return new TypeMap (type, dca == null ? null : dca.Name, members.ToArray ());
                }
 
@@ -145,15 +159,38 @@ namespace System.Runtime.Serialization.Json
                string element;
                TypeMapMember [] members;
 
+               static readonly Type [] deser_methods_args = new Type [] { typeof (StreamingContext) };
+               const BindingFlags binding_flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
+
                public TypeMap (Type type, string element, TypeMapMember [] orderedMembers)
                {
                        this.type = type;
                        this.element = element;
                        this.members = orderedMembers;
+
+                       foreach (var mi in type.GetMethods (binding_flags)) {
+                               if (mi.GetCustomAttributes (typeof (OnDeserializingAttribute), false).Length > 0)
+                                       OnDeserializing = mi;
+                               else if (mi.GetCustomAttributes (typeof (OnDeserializedAttribute), false).Length > 0)
+                                       OnDeserialized = mi;
+                               else if (mi.GetCustomAttributes (typeof (OnSerializingAttribute), false).Length > 0)
+                                       OnSerializing = mi;
+                               else if (mi.GetCustomAttributes (typeof (OnSerializedAttribute), false).Length > 0)
+                                       OnSerialized = mi;
+                       }
                }
 
-               public void Serialize (JsonSerializationWriter outputter, object graph)
+               public MethodInfo OnDeserializing { get; set; }
+               public MethodInfo OnDeserialized { get; set; }
+               public MethodInfo OnSerializing { get; set; }
+               public MethodInfo OnSerialized { get; set; }
+
+               public virtual void Serialize (JsonSerializationWriter outputter, object graph, string type)
                {
+                       if (OnSerializing != null)
+                               OnSerializing.Invoke (graph, new object [] {new StreamingContext (StreamingContextStates.All)});
+
+                       outputter.Writer.WriteAttributeString ("type", type);
                        foreach (TypeMapMember member in members) {
                                object memberObj = member.GetMemberOf (graph);
                                // FIXME: consider EmitDefaultValue
@@ -161,17 +198,36 @@ namespace System.Runtime.Serialization.Json
                                outputter.WriteObjectContent (memberObj, false, false);
                                outputter.Writer.WriteEndElement ();
                        }
+
+                       if (OnSerialized != null)
+                               OnSerialized.Invoke (graph, new object [] {new StreamingContext (StreamingContextStates.All)});
                }
 
-               public object Deserialize (JsonSerializationReader jsr)
+               internal static object CreateInstance (Type type)
+               {
+                       if (TypeMap.IsDictionary (type)) {
+                               if (type.IsGenericType)
+                                       return Activator.CreateInstance (typeof (Dictionary<,>).MakeGenericType (type.GetGenericArguments ()));
+                               else
+                                       return new Hashtable ();
+                       } else if (TypeMap.IsCollection (type)) {
+                               if (type.IsGenericType)
+                                       return Activator.CreateInstance (typeof (List<>).MakeGenericType (type.GetGenericArguments ()));
+                               else
+                                       return new ArrayList ();
+                       }
+                       else
+                               return FormatterServices.GetUninitializedObject (type);
+               }
+
+               public virtual object Deserialize (JsonSerializationReader jsr)
                {
                        XmlReader reader = jsr.Reader;
-#if NET_2_1
-                       // should it reject non-public constructor?
-                       object ret = Activator.CreateInstance (type);
-#else
-                       object ret = Activator.CreateInstance (type, true);
-#endif
+                       bool isNull = reader.GetAttribute ("type") == "null";
+
+                       object ret = isNull ? null : CreateInstance (type);
+                       if (ret != null && OnDeserializing != null)
+                               OnDeserializing.Invoke (ret, new object [] {new StreamingContext (StreamingContextStates.All)});
                        Dictionary<TypeMapMember,bool> filled = new Dictionary<TypeMapMember,bool> ();
 
                        reader.ReadStartElement ();
@@ -192,6 +248,8 @@ namespace System.Runtime.Serialization.Json
                                        reader.Skip ();
                        }
                        reader.ReadEndElement ();
+                       if (ret != null && OnDeserialized != null)
+                               OnDeserialized.Invoke (ret, new object [] {new StreamingContext (StreamingContextStates.All)});
                        return ret;
                }
        }
@@ -211,10 +269,9 @@ namespace System.Runtime.Serialization.Json
                        get { return dma == null ? mi.Name : dma.Name ?? mi.Name; }
                }
 
-               // FIXME: Fill 3.5 member in s.r.serialization.
-//             public bool EmitDefaultValue {
-//                     get { return dma != null && dma.EmitDefaultValue; }
-//             }
+               public bool EmitDefaultValue {
+                       get { return dma != null && dma.EmitDefaultValue; }
+               }
 
                public bool IsRequired {
                        get { return dma != null && dma.IsRequired; }