Author: atsushi
Date: 2008-01-22 01:50:55 -0500 (Tue, 22 Jan 2008)
New Revision: 93479

Modified:
   
trunk/olive/class/System.ServiceModel.Web/System.Runtime.Serialization.Json/ChangeLog
   
trunk/olive/class/System.ServiceModel.Web/System.Runtime.Serialization.Json/DataContractJsonSerializer.cs
   
trunk/olive/class/System.ServiceModel.Web/System.Runtime.Serialization.Json/JsonWriter.cs
   
trunk/olive/class/System.ServiceModel.Web/Test/System.Runtime.Serialization.Json/ChangeLog
   
trunk/olive/class/System.ServiceModel.Web/Test/System.Runtime.Serialization.Json/DataContractJsonSerializerTest.cs
   
trunk/olive/class/System.ServiceModel.Web/Test/System.Runtime.Serialization.Json/JsonWriterTest.cs
Log:
2008-01-22  Atsushi Enomoto  <[EMAIL PROTECTED]>

        * JsonWriter.cs : allow __type attribute. It required couple of
          changes all around the class.
        * DataContractJsonSerializer.cs : implemented large part of
          serialization support (deserialization is not done yet).

        * JsonWriterTest.cs : added test for writing __type attribute.
        * DataContractJsonSerializerTest.cs : added more random-ish tests.



Modified: 
trunk/olive/class/System.ServiceModel.Web/System.Runtime.Serialization.Json/ChangeLog
===================================================================
--- 
trunk/olive/class/System.ServiceModel.Web/System.Runtime.Serialization.Json/ChangeLog
       2008-01-22 05:22:52 UTC (rev 93478)
+++ 
trunk/olive/class/System.ServiceModel.Web/System.Runtime.Serialization.Json/ChangeLog
       2008-01-22 06:50:55 UTC (rev 93479)
@@ -1,3 +1,10 @@
+2008-01-22  Atsushi Enomoto  <[EMAIL PROTECTED]>
+
+       * JsonWriter.cs : allow __type attribute. It required couple of
+         changes all around the class.
+       * DataContractJsonSerializer.cs : implemented large part of
+         serialization support (deserialization is not done yet).
+
 2007-12-05  Atsushi Enomoto  <[EMAIL PROTECTED]>
 
        * DataContractJsonSerializer.cs :

Modified: 
trunk/olive/class/System.ServiceModel.Web/System.Runtime.Serialization.Json/DataContractJsonSerializer.cs
===================================================================
--- 
trunk/olive/class/System.ServiceModel.Web/System.Runtime.Serialization.Json/DataContractJsonSerializer.cs
   2008-01-22 05:22:52 UTC (rev 93478)
+++ 
trunk/olive/class/System.ServiceModel.Web/System.Runtime.Serialization.Json/DataContractJsonSerializer.cs
   2008-01-22 06:50:55 UTC (rev 93479)
@@ -26,9 +26,12 @@
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 using System;
+using System.Collections;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
+using System.Globalization;
 using System.IO;
+using System.Reflection;
 using System.Text;
 using System.Xml;
 
@@ -36,7 +39,7 @@
 {
        public sealed class DataContractJsonSerializer : XmlObjectSerializer
        {
-               DataContractSerializer impl;
+               const string default_root_name = "root";
 
                #region lengthy constructor list
 
@@ -46,7 +49,7 @@
                }
 
                public DataContractJsonSerializer (Type type, IEnumerable<Type> 
knownTypes)
-                       : this (type, "root", Type.EmptyTypes)
+                       : this (type, default_root_name, Type.EmptyTypes)
                {
                }
 
@@ -56,47 +59,58 @@
                }
 
                public DataContractJsonSerializer (Type type, 
XmlDictionaryString rootName)
-                       : this (type, rootName, Type.EmptyTypes)
+                       : this (type, rootName != null ? rootName.Value : 
default_root_name, Type.EmptyTypes)
                {
                }
 
                public DataContractJsonSerializer (Type type, string rootName, 
IEnumerable<Type> knownTypes)
-                       : this (type, new XmlDictionary ().Add (rootName), 
knownTypes)
+                       : this (type, rootName, knownTypes, int.MaxValue, 
false, null, true)
                {
                }
 
-               [MonoTODO]
                public DataContractJsonSerializer (Type type, 
XmlDictionaryString rootName, IEnumerable<Type> knownTypes)
+                       : this (type, rootName != null ? rootName.Value : 
default_root_name, knownTypes)
                {
-                       impl = new DataContractSerializer (type, rootName, 
XmlDictionaryString.Empty, knownTypes);
-                       root = rootName;
                }
 
-               [MonoTODO]
                public DataContractJsonSerializer (Type type, IEnumerable<Type> 
knownTypes, int maxItemsInObjectGraph, bool ignoreExtensionDataObject, 
IDataContractSurrogate dataContractSurrogate, bool alwaysEmitTypeInformation)
+                       : this (type, default_root_name, knownTypes, 
maxItemsInObjectGraph, ignoreExtensionDataObject, dataContractSurrogate, 
alwaysEmitTypeInformation)
                {
-                       //impl = new DataContractSerializer (type, knownTypes, 
maxItemsInObjectGraph, ignoreExtensionDataObject, dataContractSurrogate, 
alwaysEmitTypeInformation);
-                       throw new NotImplementedException ();
                }
 
                [MonoTODO]
                public DataContractJsonSerializer (Type type, string rootName, 
IEnumerable<Type> knownTypes, int maxItemsInObjectGraph, bool 
ignoreExtensionDataObject, IDataContractSurrogate dataContractSurrogate, bool 
alwaysEmitTypeInformation)
                {
-//                     impl = new DataContractSerializer (type, rootName, 
String.Empty, knownTypes, maxItemsInObjectGraph, ignoreExtensionDataObject, 
dataContractSurrogate, alwaysEmitTypeInformation);
-                       throw new NotImplementedException ();
+                       if (type == null)
+                               throw new ArgumentNullException ("type");
+                       if (rootName == null)
+                               throw new ArgumentNullException ("rootName");
+                       if (maxItemsInObjectGraph < 0)
+                               throw new ArgumentOutOfRangeException 
("maxItemsInObjectGraph");
+
+                       List<Type> types = new List<Type> ();
+                       types.Add (type);
+                       if (knownTypes != null)
+                               types.AddRange (knownTypes);
+
+                       this.type = type;
+                       known_types = new ReadOnlyCollection<Type> (types);
+                       root = rootName;
+                       max_items = maxItemsInObjectGraph;
+                       ignore_extension = ignoreExtensionDataObject;
+                       surrogate = dataContractSurrogate;
+                       always_emit_type = alwaysEmitTypeInformation;
                }
 
-               [MonoTODO]
                public DataContractJsonSerializer (Type type, 
XmlDictionaryString rootName, IEnumerable<Type> knownTypes, int 
maxItemsInObjectGraph, bool ignoreExtensionDataObject, IDataContractSurrogate 
dataContractSurrogate, bool alwaysEmitTypeInformation)
+                       : this (type, rootName != null ? rootName.Value : null, 
knownTypes, maxItemsInObjectGraph, ignoreExtensionDataObject, 
dataContractSurrogate, alwaysEmitTypeInformation)
                {
-//                     impl = new DataContractSerializer (type, rootName, 
XmlDictionaryString.Empty, knownTypes, maxItemsInObjectGraph, 
ignoreExtensionDataObject, dataContractSurrogate, alwaysEmitTypeInformation);
-                       throw new NotImplementedException ();
                }
 
                #endregion
 
                Type type;
-               XmlDictionaryString root;
+               string root;
                ReadOnlyCollection<Type> known_types;
                int max_items;
                bool ignore_extension;
@@ -105,126 +119,384 @@
 
                [MonoTODO]
                public IDataContractSurrogate DataContractSurrogate {
-//                     get { return surrogate; }
-                       get { return impl.DataContractSurrogate; }
+                       get { return surrogate; }
                }
 
                [MonoTODO]
                public bool IgnoreExtensionDataObject {
-//                     get { return ignore_extension; }
-                       get { return impl.IgnoreExtensionDataObject; }
+                       get { return ignore_extension; }
                }
 
                [MonoTODO]
                public ReadOnlyCollection<Type> KnownTypes {
-//                     get { return known_types; }
-                       get { return impl.KnownTypes; }
+                       get { return known_types; }
                }
 
-               [MonoTODO]
                public int MaxItemsInObjectGraph {
-//                     get { return max_items; }
-                       get { return impl.MaxItemsInObjectGraph; }
+                       get { return max_items; }
                }
 
-               [MonoTODO]
                public override bool IsStartObject (XmlReader reader)
                {
-                       return impl.IsStartObject (reader);
+                       if (reader == null)
+                               throw new ArgumentNullException ("reader");
+                       reader.MoveToContent ();
+                       return reader.IsStartElement (root, String.Empty);
                }
 
-               [MonoTODO]
                public override bool IsStartObject (XmlDictionaryReader reader)
                {
-                       return impl.IsStartObject (reader);
+                       return IsStartObject ((XmlReader) reader);
                }
 
-               [MonoTODO]
                public override object ReadObject (Stream stream)
                {
                        return ReadObject 
(JsonReaderWriterFactory.CreateJsonReader (stream, new 
XmlDictionaryReaderQuotas ()));
                }
 
-               [MonoTODO]
                public override object ReadObject (XmlDictionaryReader reader)
                {
-                       return impl.ReadObject (reader);
+                       return ReadObject (reader, true);
                }
 
-               [MonoTODO]
                public override object ReadObject (XmlReader reader)
                {
-                       return impl.ReadObject (reader);
+                       return ReadObject (reader, true);
                }
 
-               [MonoTODO]
                public override object ReadObject (XmlDictionaryReader reader, 
bool verifyObjectName)
                {
-                       return impl.ReadObject (reader, verifyObjectName);
+                       return ReadObject ((XmlReader) reader, 
verifyObjectName);
                }
 
                [MonoTODO]
                public override object ReadObject (XmlReader reader, bool 
verifyObjectName)
                {
-                       return impl.ReadObject (reader, verifyObjectName);
+                       if (reader == null)
+                               throw new ArgumentNullException ("reader");
+                       if (verifyObjectName && !IsStartObject (reader))
+                               throw new SerializationException (String.Format 
("Expected element was '{0}', but the actual input element was '{1}' in 
namespace '{2}'", root, reader.LocalName, reader.NamespaceURI));
+
+                       throw new NotImplementedException ();
                }
 
-               [MonoTODO]
                public override void WriteObject (Stream stream, object graph)
                {
                        WriteObject (JsonReaderWriterFactory.CreateJsonWriter 
(stream), graph);
                }
 
-               [MonoTODO]
                public override void WriteObject (XmlWriter writer, object 
graph)
                {
-                       impl.WriteObject (writer as XmlDictionaryWriter ?? 
XmlDictionaryWriter.CreateDictionaryWriter (writer), graph);
-               }
-
-               [MonoTODO]
-               public override void WriteObject (XmlDictionaryWriter writer, 
object graph)
-               {
                        try {
-                               impl.WriteObject (writer, graph);
+                               WriteStartObject (writer, graph);
+                               WriteObjectContent (writer, graph);
+                               WriteEndObject (writer);
+                       } catch (NotImplementedException) {
+                               throw;
+                       } catch (InvalidDataContractException) {
+                               throw;
                        } catch (Exception ex) {
                                throw new SerializationException (String.Format 
("There was an error during serialization for object of type {0}", graph != 
null ? graph.GetType () : null), ex);
                        }
                }
 
-               [MonoTODO]
+               public override void WriteObject (XmlDictionaryWriter writer, 
object graph)
+               {
+                       WriteObject ((XmlWriter) writer, graph);
+               }
+
                public override void WriteStartObject (XmlDictionaryWriter 
writer, object graph)
                {
-                       impl.WriteStartObject (writer, graph);
+                       WriteStartObject ((XmlWriter) writer, graph);
                }
 
-               [MonoTODO]
                public override void WriteStartObject (XmlWriter writer, object 
graph)
                {
-                       impl.WriteStartObject (writer, graph);
+                       if (writer == null)
+                               throw new ArgumentNullException ("writer");
+                       writer.WriteStartElement (root);
                }
 
-               [MonoTODO]
                public override void WriteObjectContent (XmlDictionaryWriter 
writer, object graph)
                {
-                       impl.WriteObjectContent (writer, graph);
+                       WriteObjectContent ((XmlWriter) writer, graph);
                }
 
                [MonoTODO]
                public override void WriteObjectContent (XmlWriter writer, 
object graph)
                {
-                       impl.WriteObjectContent (writer, graph);
+                       new Outputter (this, writer, type, 
always_emit_type).WriteObjectContent (graph, true, false);
                }
 
-               [MonoTODO]
                public override void WriteEndObject (XmlDictionaryWriter writer)
                {
-                       impl.WriteEndObject (writer);
+                       WriteEndObject ((XmlWriter) writer);
                }
 
-               [MonoTODO]
                public override void WriteEndObject (XmlWriter writer)
                {
-                       impl.WriteEndObject (writer);
+                       if (writer == null)
+                               throw new ArgumentNullException ("writer");
+                       writer.WriteEndElement ();
                }
        }
+
+       class Outputter
+       {
+               DataContractJsonSerializer serializer;
+               XmlWriter writer;
+               int serialized_object_count;
+               bool always_emit_type;
+               Dictionary<Type, TypeMap> typemaps = new Dictionary<Type, 
TypeMap> ();
+               Type root_type;
+
+               public Outputter (DataContractJsonSerializer serializer, 
XmlWriter writer, Type rootType, bool alwaysEmitTypeInformation)
+               {
+                       this.serializer = serializer;
+                       this.writer = writer;
+                       this.root_type = rootType;
+                       this.always_emit_type = alwaysEmitTypeInformation;
+               }
+
+               public XmlWriter Writer {
+                       get { return writer; }
+               }
+
+               public void WriteObjectContent (object graph, bool top, bool 
outputTypeName)
+               {
+                       if (graph == null) {
+                               if (top)
+                                       GetTypeMap (root_type); // to make sure 
to reject invalid contracts
+                               return;
+                       }
+
+                       if (serialized_object_count ++ == 
serializer.MaxItemsInObjectGraph)
+                               throw new SerializationException (String.Format 
("The object graph exceeded the maximum object count '{0}' specified in the 
serializer", serializer.MaxItemsInObjectGraph));
+
+                       switch (Type.GetTypeCode (graph.GetType ())) {
+                       case TypeCode.String:
+                               writer.WriteString ((string) graph);
+                               break;
+                       case TypeCode.Single:
+                       case TypeCode.Double:
+                       case TypeCode.Decimal:
+                               if (always_emit_type)
+                                       writer.WriteAttributeString ("type", 
"number");
+                               writer.WriteString (((IFormattable) 
graph).ToString ("R", CultureInfo.InvariantCulture));
+                               break;
+                       case TypeCode.Byte:
+                       case TypeCode.SByte:
+                       case TypeCode.Int16:
+                       case TypeCode.Int32:
+                       case TypeCode.Int64:
+                       case TypeCode.UInt16:
+                       case TypeCode.UInt32:
+                       case TypeCode.UInt64:
+                               if (always_emit_type)
+                                       writer.WriteAttributeString ("type", 
"number");
+                               if (graph.GetType ().IsEnum)
+                                       graph = ((IConvertible) graph).ToType 
(Enum.GetUnderlyingType (graph.GetType ()), CultureInfo.InvariantCulture);
+                               writer.WriteString (((IFormattable) 
graph).ToString ("G", CultureInfo.InvariantCulture));
+                               break;
+                       case TypeCode.Boolean:
+                               if ((bool) graph)
+                                       writer.WriteString ("true");
+                               else
+                                       writer.WriteString ("false");
+                               break;
+                       default:
+                               if (graph is ICollection) { // array
+                                       writer.WriteAttributeString ("type", 
"array");
+                                       foreach (object o in (ICollection) 
graph) {
+                                               writer.WriteStartElement 
("item");
+                                               // when it is typed, then no 
need to output "__type"
+                                               WriteObjectContent (o, false, 
!(graph is Array && graph.GetType ().GetElementType () != typeof (object)));
+                                               writer.WriteEndElement ();
+                                       }
+                               } else { // object
+                                       TypeMap tm = GetTypeMap (graph.GetType 
());
+                                       if (tm != null) {
+                                               // FIXME: I'm not sure how it 
is determined whether __type is written or not...
+                                               if (outputTypeName)
+                                                       
writer.WriteAttributeString ("__type", FormatTypeName (graph.GetType ()));
+                                               if (always_emit_type)
+                                                       
writer.WriteAttributeString ("type", "object");
+                                               tm.Serialize (this, graph);
+                                       }
+                                       else
+                                               // it does not emit 
type="object" (as the graph is regarded as a string)
+//                                             writer.WriteString 
(graph.ToString ());
+throw new InvalidDataContractException (String.Format ("Type {0} cannot be 
serialized by this JSON serializer", graph.GetType ()));
+                               }
+                               break;
+                       }
+               }
+
+               string FormatTypeName (Type type)
+               {
+                       return type.Namespace == null ? type.Name : 
String.Format ("{0}:#{1}", type.Name, type.Namespace);
+               }
+
+               TypeMap GetTypeMap (Type type)
+               {
+                       TypeMap map;
+                       if (!typemaps.TryGetValue (type, out map)) {
+                               map = TypeMap.CreateTypeMap (type);
+                               typemaps [type] = map;
+                       }
+                       return map;
+               }
+       }
+
+       class TypeMap
+       {
+               static bool IsInvalidNCName (string name)
+               {
+                       if (name == null || name.Length == 0)
+                               return true;
+                       try {
+                               XmlConvert.VerifyNCName (name);
+                       } catch (XmlException) {
+                               return true;
+                       }
+                       return false;
+               }
+
+               public static TypeMap CreateTypeMap (Type type)
+               {
+                       object [] atts = type.GetCustomAttributes (typeof 
(DataContractAttribute), true);
+                       if (atts.Length == 1)
+                               return CreateTypeMap (type, 
(DataContractAttribute) atts [0]);
+
+                       atts = type.GetCustomAttributes (typeof 
(SerializableAttribute), false);
+                       if (atts.Length == 1)
+                               return CreateTypeMap (type, null);
+
+                       return null;
+               }
+
+               static TypeMap CreateTypeMap (Type type, DataContractAttribute 
dca)
+               {
+                       if (dca != null && dca.Name != null && IsInvalidNCName 
(dca.Name))
+                               throw new InvalidDataContractException 
(String.Format ("DataContractAttribute for type '{0}' has an invalid name", 
type));
+
+                       List<TypeMapMember> members = new List<TypeMapMember> 
();
+
+                       foreach (FieldInfo fi in type.GetFields 
(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) {
+                               if (dca != null) {
+                                       object [] atts = fi.GetCustomAttributes 
(typeof (DataMemberAttribute), true);
+                                       if (atts.Length == 0)
+                                               continue;
+                                       DataMemberAttribute dma = 
(DataMemberAttribute) atts [0];
+                                       members.Add (new TypeMapField (fi, 
dma));
+                               } else {
+                                       if (fi.GetCustomAttributes (typeof 
(NonSerializedAttribute), 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)) {
+                                       if (pi.GetIndexParameters ().Length > 0)
+                                               continue;
+                                       if (!pi.CanRead || !pi.CanWrite)
+                                               throw new 
InvalidDataContractException (String.Format ("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; });
+                       return new TypeMap (type, dca == null ? null : 
dca.Name, members.ToArray ());
+               }
+
+               Type type;
+               string element;
+               TypeMapMember [] members;
+
+               public TypeMap (Type type, string element, TypeMapMember [] 
orderedMembers)
+               {
+                       this.type = type;
+                       this.element = element;
+                       this.members = orderedMembers;
+               }
+
+               public void Serialize (Outputter outputter, object graph)
+               {
+                       foreach (TypeMapMember member in members) {
+                               object memberObj = member.GetMemberOf (graph);
+                               // FIXME: consider EmitDefaultValue
+                               outputter.Writer.WriteStartElement 
(member.Name);
+                               outputter.WriteObjectContent (memberObj, false, 
false);
+                               outputter.Writer.WriteEndElement ();
+                       }
+               }
+       }
+
+       abstract class TypeMapMember
+       {
+               MemberInfo mi;
+               DataMemberAttribute dma;
+
+               protected TypeMapMember (MemberInfo mi, DataMemberAttribute dma)
+               {
+                       this.mi = mi;
+                       this.dma = dma;
+               }
+
+               public string Name {
+                       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 IsRequired {
+                       get { return dma != null && dma.IsRequired; }
+               }
+
+               public int Order {
+                       get { return dma != null ? dma.Order : -1; }
+               }
+
+               public abstract object GetMemberOf (object owner);
+       }
+
+       class TypeMapField : TypeMapMember
+       {
+               FieldInfo field;
+
+               public TypeMapField (FieldInfo fi, DataMemberAttribute dma)
+                       : base (fi, dma)
+               {
+                       this.field = fi;
+               }
+
+               public override object GetMemberOf (object owner)
+               {
+                       return field.GetValue (owner);
+               }
+       }
+
+       class TypeMapProperty : TypeMapMember
+       {
+               PropertyInfo property;
+
+               public TypeMapProperty (PropertyInfo pi, DataMemberAttribute 
dma)
+                       : base (pi, dma)
+               {
+                       this.property = pi;
+               }
+
+               public override object GetMemberOf (object owner)
+               {
+                       return property.GetValue (owner, null);
+               }
+       }
 }

Modified: 
trunk/olive/class/System.ServiceModel.Web/System.Runtime.Serialization.Json/JsonWriter.cs
===================================================================
--- 
trunk/olive/class/System.ServiceModel.Web/System.Runtime.Serialization.Json/JsonWriter.cs
   2008-01-22 05:22:52 UTC (rev 93478)
+++ 
trunk/olive/class/System.ServiceModel.Web/System.Runtime.Serialization.Json/JsonWriter.cs
   2008-01-22 06:50:55 UTC (rev 93479)
@@ -51,7 +51,7 @@
                WriteState state;
                Stack<ElementType> element_kinds = new Stack<ElementType> ();
                Stack<bool> first_content_flags = new Stack<bool> ();
-               string attr_value;
+               string attr_name, attr_value, runtime_type;
 
                public JsonWriter (Stream stream, Encoding encoding, bool 
closeOutput)
                {
@@ -249,12 +249,13 @@
                        if (!String.IsNullOrEmpty (prefix))
                                throw new ArgumentException ("Non-empty prefix 
is not allowed in this XmlDictionaryWriter");
 
-                       if (localName != "type")
-                               throw new ArgumentException ("Only 'type' 
attribute is allowed in this XmlDictionaryWriter");
+                       if (localName != "type" && localName != "__type")
+                               throw new ArgumentException ("Only 'type' and 
'__type' are allowed as an attribute name in this XmlDictionaryWriter");
 
                        if (state != WriteState.Element)
                                throw new InvalidOperationException 
(String.Format ("Attribute cannot be written in {0} mode", state));
 
+                       attr_name = localName;
                        state = WriteState.Attribute;
                }
 
@@ -265,32 +266,36 @@
                        if (state != WriteState.Attribute)
                                throw new XmlException ("Cannot close 
attribute, as this XmlDictionaryWriter is not at attribute state");
 
-                       switch (attr_value) {
-                       case "object":
-                               element_kinds.Pop ();
-                               element_kinds.Push (ElementType.Object);
-                               output.Write ('{');
-                               break;
-                       case "array":
-                               element_kinds.Pop ();
-                               element_kinds.Push (ElementType.Array);
-                               output.Write ('[');
-                               break;
-                       case "number":
-                               element_kinds.Pop ();
-                               element_kinds.Push (ElementType.Number);
-                               break;
-                       case "boolean":
-                               element_kinds.Pop ();
-                               element_kinds.Push (ElementType.Boolean);
-                               break;
-                       case "string":
-                               element_kinds.Pop ();
-                               element_kinds.Push (ElementType.String);
-                               break;
-                       default:
-                               throw new XmlException (String.Format 
("Unexpected type attribute value '{0}'", attr_value));
+                       if (attr_name == "type") {
+                               switch (attr_value) {
+                               case "object":
+                                       element_kinds.Pop ();
+                                       element_kinds.Push (ElementType.Object);
+                                       output.Write ('{');
+                                       break;
+                               case "array":
+                                       element_kinds.Pop ();
+                                       element_kinds.Push (ElementType.Array);
+                                       output.Write ('[');
+                                       break;
+                               case "number":
+                                       element_kinds.Pop ();
+                                       element_kinds.Push (ElementType.Number);
+                                       break;
+                               case "boolean":
+                                       element_kinds.Pop ();
+                                       element_kinds.Push 
(ElementType.Boolean);
+                                       break;
+                               case "string":
+                                       element_kinds.Pop ();
+                                       element_kinds.Push (ElementType.String);
+                                       break;
+                               default:
+                                       throw new XmlException (String.Format 
("Unexpected type attribute value '{0}'", attr_value));
+                               }
                        }
+                       else
+                               runtime_type = attr_value;
 
                        state = WriteState.Element;
                        attr_value = null;
@@ -307,6 +312,15 @@
                                output.Write ('"');
 
                        first_content_flags.Push (true);
+
+                       if (runtime_type != null) {
+                               output.Write ("\"__type\":\"");
+                               output.Write (runtime_type);
+                               output.Write ('\"');
+                               runtime_type = null;
+                               first_content_flags.Pop ();
+                               first_content_flags.Push (false);
+                       }
                }
 
                public override void WriteString (string text)

Modified: 
trunk/olive/class/System.ServiceModel.Web/Test/System.Runtime.Serialization.Json/ChangeLog
===================================================================
--- 
trunk/olive/class/System.ServiceModel.Web/Test/System.Runtime.Serialization.Json/ChangeLog
  2008-01-22 05:22:52 UTC (rev 93478)
+++ 
trunk/olive/class/System.ServiceModel.Web/Test/System.Runtime.Serialization.Json/ChangeLog
  2008-01-22 06:50:55 UTC (rev 93479)
@@ -1,3 +1,8 @@
+2008-01-22  Atsushi Enomoto  <[EMAIL PROTECTED]>
+
+       * JsonWriterTest.cs : added test for writing __type attribute.
+       * DataContractJsonSerializerTest.cs : added more random-ish tests.
+
 2007-12-05  Atsushi Enomoto  <[EMAIL PROTECTED]>
 
        * DataContractJsonSerializerTest.cs :

Modified: 
trunk/olive/class/System.ServiceModel.Web/Test/System.Runtime.Serialization.Json/DataContractJsonSerializerTest.cs
===================================================================
--- 
trunk/olive/class/System.ServiceModel.Web/Test/System.Runtime.Serialization.Json/DataContractJsonSerializerTest.cs
  2008-01-22 05:22:52 UTC (rev 93478)
+++ 
trunk/olive/class/System.ServiceModel.Web/Test/System.Runtime.Serialization.Json/DataContractJsonSerializerTest.cs
  2008-01-22 06:50:55 UTC (rev 93479)
@@ -906,7 +906,24 @@
                }
 
                [Test]
+               public void MaxItemsInObjectGraph1 ()
+               {
+                       // object count == maximum
+                       DataContractJsonSerializer s = new 
DataContractJsonSerializer (typeof (DCEmpty), null, 1, false, null, false);
+                       s.WriteObject (XmlWriter.Create (TextWriter.Null), new 
DCEmpty ());
+               }
+
+               [Test]
                [ExpectedException (typeof (SerializationException))]
+               public void MaxItemsInObjectGraph2 ()
+               {
+                       // object count > maximum
+                       DataContractJsonSerializer s = new 
DataContractJsonSerializer (typeof (DCSimple1), null, 1, false, null, false);
+                       s.WriteObject (XmlWriter.Create (TextWriter.Null), new 
DCSimple1 ());
+               }
+
+               [Test]
+               [ExpectedException (typeof (SerializationException))]
                public void DeserializeEnumByName ()
                {
                        // enum is parsed into long
@@ -974,13 +991,36 @@
                }
 
                [Test]
-               public void ReadObjectVerifyObjectName ()
+               public void ReadObjectVerifyObjectNameFalse ()
                {
-                       string xml = @"<any><Member1 
xmlns=""http://schemas.datacontract.org/2004/07/MonoTests.System.Runtime.Serialization"";>bar</Member1></any>";
-                       new DataContractJsonSerializer (typeof 
(VerifyObjectNameTestData))
+                       string xml = @"<any><Member1>bar</Member1></any>";
+                       object o = new DataContractJsonSerializer (typeof 
(VerifyObjectNameTestData))
                                .ReadObject (XmlReader.Create (new StringReader 
(xml)), false);
+                       Assert.IsTrue (o is VerifyObjectNameTestData, "#1");
+
+                       string xml2 = @"<any><x:Member1 
xmlns:x=""http://schemas.datacontract.org/2004/07/MonoTests.System.Runtime.Serialization"";>bar</x:Member1></any>";
+                       o = new DataContractJsonSerializer (typeof 
(VerifyObjectNameTestData))
+                               .ReadObject (XmlReader.Create (new StringReader 
(xml2)), false);
+                       Assert.IsTrue (o is VerifyObjectNameTestData, "#2");
                }
 
+               [Test]
+               [ExpectedException (typeof (SerializationException))]
+               public void ReadObjectVerifyObjectNameTrue ()
+               {
+                       string xml = @"<any><Member1>bar</Member1></any>";
+                       new DataContractJsonSerializer (typeof 
(VerifyObjectNameTestData))
+                               .ReadObject (XmlReader.Create (new StringReader 
(xml)), true);
+               }
+
+               [Test] // member name is out of scope
+               public void ReadObjectVerifyObjectNameTrue2 ()
+               {
+                       string xml = @"<root><Member2>bar</Member2></root>";
+                       new DataContractJsonSerializer (typeof 
(VerifyObjectNameTestData))
+                               .ReadObject (XmlReader.Create (new StringReader 
(xml)), true);
+               }
+
                private object Deserialize (string xml, Type type)
                {
                        DataContractJsonSerializer ser = new 
DataContractJsonSerializer (type);
@@ -988,6 +1028,15 @@
                        return ser.ReadObject (xr);
                }
 
+               [Test]
+               public void IsStartObject ()
+               {
+                       DataContractJsonSerializer s = new 
DataContractJsonSerializer (typeof (DCSimple1));
+                       Assert.IsTrue (s.IsStartObject (XmlReader.Create (new 
StringReader ("<root></root>"))), "#1");
+                       Assert.IsFalse (s.IsStartObject (XmlReader.Create (new 
StringReader ("<dummy></dummy>"))), "#2");
+                       Assert.IsFalse (s.IsStartObject (XmlReader.Create (new 
StringReader ("<Foo></Foo>"))), "#3");
+                       Assert.IsFalse (s.IsStartObject (XmlReader.Create (new 
StringReader ("<root xmlns='urn:foo'></root>"))), "#4");
+               }
        }
  
        public enum Colors {

Modified: 
trunk/olive/class/System.ServiceModel.Web/Test/System.Runtime.Serialization.Json/JsonWriterTest.cs
===================================================================
--- 
trunk/olive/class/System.ServiceModel.Web/Test/System.Runtime.Serialization.Json/JsonWriterTest.cs
  2008-01-22 05:22:52 UTC (rev 93478)
+++ 
trunk/olive/class/System.ServiceModel.Web/Test/System.Runtime.Serialization.Json/JsonWriterTest.cs
  2008-01-22 06:50:55 UTC (rev 93479)
@@ -468,10 +468,20 @@
                        w.WriteAttributeString ("type", "object");
                        w.WriteStartElement (String.Empty);
                        // It is regarded as invalid name in JSON. However,
-                       // I don't think there is such specification in JSON.
+                       // I don't think there is such limitation in JSON 
specification.
                }
 
                [Test]
+               public void WriteStartElementWithRuntimeTypeName ()
+               {
+                       w.WriteStartElement ("root");
+                       w.WriteAttributeString ("type", "object");
+                       w.WriteAttributeString ("__type", 
"FooType:#FooNamespace");
+                       w.Close ();
+                       Assert.AreEqual 
(@"{""__type"":""FooType:#FooNamespace""}", ResultString);
+               }
+
+               [Test]
                public void WriteStartElementWeirdName ()
                {
                        w.WriteStartElement ("root");

_______________________________________________
Mono-patches maillist  -  [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches

Reply via email to