New tests.
[mono.git] / mcs / class / System.ServiceModel.Web / System.Runtime.Serialization.Json / JsonSerializationReader.cs
index 60f8f106bf7a0f84f2a075537844f9756bddd554..87cb0dc1e2648706b139b82b21b369c47bda0bb3 100644 (file)
@@ -71,6 +71,8 @@ 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));
 
+                       bool isNull = reader.GetAttribute ("type") == "null";
+
                        switch (Type.GetTypeCode (type)) {
                        case TypeCode.DBNull:
                                string dbn = reader.ReadElementContentAsString ();
@@ -78,7 +80,12 @@ namespace System.Runtime.Serialization.Json
                                        throw new SerializationException (String.Format ("The only expected DBNull value string is '{{}}'. Tha actual input was '{0}'.", dbn));
                                return DBNull.Value;
                        case TypeCode.String:
-                               return reader.ReadElementContentAsString ();
+                               if (isNull) {
+                                       reader.ReadElementContentAsString ();
+                                       return null;
+                               }
+                               else
+                                       return reader.ReadElementContentAsString ();
                        case TypeCode.Single:
                                return reader.ReadElementContentAsFloat ();
                        case TypeCode.Double:
@@ -93,25 +100,36 @@ namespace System.Runtime.Serialization.Json
                        case TypeCode.UInt32:
                                int i = reader.ReadElementContentAsInt ();
                                if (type.IsEnum)
-                                       return Enum.ToObject (type, i);
+                                       return Enum.ToObject (type, (object)i);
                                else
-                                       return Convert.ChangeType (i, type);
+                                       return Convert.ChangeType (i, type, null);
                        case TypeCode.Int64:
                        case TypeCode.UInt64:
                                long l = reader.ReadElementContentAsLong ();
                                if (type.IsEnum)
-                                       return Enum.ToObject (type, l);
+                                       return Enum.ToObject (type, (object)l);
                                else
-                                       return Convert.ChangeType (l, type);
+                                       return Convert.ChangeType (l, type, null);
                        case TypeCode.Boolean:
                                return reader.ReadElementContentAsBoolean ();
+                       case TypeCode.DateTime:
+                               // it does not use ReadElementContentAsDateTime(). Different string format.
+                               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)));
                        default:
                                if (type == typeof (Guid)) {
                                        return new Guid (reader.ReadElementContentAsString ());
                                } else if (type == typeof (Uri)) {
-                                       return new Uri (reader.ReadElementContentAsString ());
+                                       if (isNull) {
+                                               reader.ReadElementContentAsString ();
+                                               return null;
+                                       }
+                                       else
+                                               return new Uri (reader.ReadElementContentAsString ());
                                } else if (type == typeof (XmlQualifiedName)) {
-                                       string s = reader.ReadElementContentAsString ();
+                                       s = reader.ReadElementContentAsString ();
                                        int idx = s.IndexOf (':');
                                        return idx < 0 ? new XmlQualifiedName (s) : new XmlQualifiedName (s.Substring (0, idx), s.Substring (idx + 1));
                                } else if (type != typeof (object)) {
@@ -142,7 +160,19 @@ namespace System.Runtime.Serialization.Json
                                foreach (Type t in serializer.KnownTypes)
                                        if (t.FullName == name)
                                                return t;
-                       return Type.GetType (name, false);
+                       var ret = root_type.Assembly.GetType (name, false) ?? Type.GetType (name, false);
+                       if (ret != null)
+                               return ret;
+#if !NET_2_1 // how to do that in ML?
+                       // We probably have to iterate all the existing
+                       // assemblies that are loaded in current domain.
+                       foreach (var ass in AppDomain.CurrentDomain.GetAssemblies ()) {
+                               ret = ass.GetType (name, false);
+                               if (ret != null)
+                                       return ret;
+                       }
+#endif
+                       return null;
                }
 
                object ReadInstanceDrivenObject ()
@@ -213,9 +243,10 @@ namespace System.Runtime.Serialization.Json
                                return type.GetElementType ();
                        if (type.IsGenericType) {
                                // returns T for ICollection<T>
-                               Type gt = type.GetGenericTypeDefinition ();
-                               if (gt == typeof (ICollection<>))
-                                       return type.GetGenericArguments () [0];
+                               Type [] ifaces = type.GetInterfaces ();
+                               foreach (Type i in ifaces)
+                                       if (i.IsGenericType && i.GetGenericTypeDefinition ().Equals (typeof (ICollection<>)))
+                                               return i.GetGenericArguments () [0];
                        }
                        if (typeof (IList).IsAssignableFrom (type))
                                // return typeof(object) for mere collection.
@@ -228,10 +259,15 @@ namespace System.Runtime.Serialization.Json
                {
                        reader.ReadStartElement ();
                        object ret;
+                       if (collectionType.IsInterface)
+                               collectionType = typeof (List<>).MakeGenericType (elementType);
                        if (typeof (IList).IsAssignableFrom (collectionType)) {
-                               IList c = collectionType.IsArray ?
-                                       new ArrayList () :
-                                       (IList) Activator.CreateInstance (collectionType);
+#if NET_2_1
+                               Type listType = collectionType.IsArray ? typeof (List<>).MakeGenericType (elementType) : null;
+#else
+                               Type listType = collectionType.IsArray ? typeof (ArrayList) : null;
+#endif
+                               IList c = (IList) Activator.CreateInstance (listType ?? collectionType);
                                for (reader.MoveToContent (); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ()) {
                                        if (!reader.IsStartElement ("item"))
                                                throw SerializationError (String.Format ("Expected element 'item', but found '{0}' in namespace '{1}'", reader.LocalName, reader.NamespaceURI));
@@ -239,10 +275,26 @@ namespace System.Runtime.Serialization.Json
                                        object elem = ReadObject (et ?? typeof (object));
                                        c.Add (elem);
                                }
+#if NET_2_1
+                               if (collectionType.IsArray) {
+                                       Array array = Array.CreateInstance (elementType, c.Count);
+                                       c.CopyTo (array, 0);
+                                       ret = array;
+                               }
+                               else
+                                       ret = c;
+#else
                                ret = collectionType.IsArray ? ((ArrayList) c).ToArray (elementType) : c;
+#endif
                        } else {
                                object c = Activator.CreateInstance (collectionType);
                                MethodInfo add = collectionType.GetMethod ("Add", new Type [] {elementType});
+                               if (add == null) {
+                                       var icoll = typeof (ICollection<>).MakeGenericType (elementType);
+                                       if (icoll.IsAssignableFrom (c.GetType ()))
+                                               add = icoll.GetMethod ("Add");
+                               }
+                               
                                for (reader.MoveToContent (); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ()) {
                                        if (!reader.IsStartElement ("item"))
                                                throw SerializationError (String.Format ("Expected element 'item', but found '{0}' in namespace '{1}'", reader.LocalName, reader.NamespaceURI));