Merge pull request #1508 from slluis/fix-20966
[mono.git] / mcs / class / System.ServiceModel.Web / System.Runtime.Serialization.Json / DataContractJsonSerializer.cs
1 //
2 // DataContractJsonSerializer.cs
3 //
4 // Author:
5 //      Atsushi Enomoto  <atsushi@ximian.com>
6 //
7 // Copyright (C) 2007-2008 Novell, Inc (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 using System;
29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Collections.ObjectModel;
32 using System.Globalization;
33 using System.IO;
34 using System.Linq;
35 using System.Reflection;
36 using System.Text;
37 using System.Xml;
38
39 namespace System.Runtime.Serialization.Json
40 {
41         public sealed class DataContractJsonSerializer : XmlObjectSerializer
42         {
43                 const string default_root_name = "root";
44
45                 #region lengthy constructor list
46
47                 public DataContractJsonSerializer (Type type)
48                         : this (type, Type.EmptyTypes)
49                 {
50                 }
51
52                 public DataContractJsonSerializer (Type type, IEnumerable<Type> knownTypes)
53                         : this (type, default_root_name, knownTypes)
54                 {
55                 }
56
57                 public DataContractJsonSerializer (Type type, string rootName)
58                         : this (type, rootName, Type.EmptyTypes)
59                 {
60                 }
61
62                 public DataContractJsonSerializer (Type type, XmlDictionaryString rootName)
63                         : this (type, rootName != null ? rootName.Value : default_root_name, Type.EmptyTypes)
64                 {
65                 }
66
67                 public DataContractJsonSerializer (Type type, string rootName, IEnumerable<Type> knownTypes)
68                         : this (type, rootName, knownTypes, int.MaxValue, false, false)
69                 {
70                 }
71
72                 public DataContractJsonSerializer (Type type, XmlDictionaryString rootName, IEnumerable<Type> knownTypes)
73                         : this (type, rootName != null ? rootName.Value : default_root_name, knownTypes)
74                 {
75                 }
76
77                 DataContractJsonSerializer(Type type, string rootName, IEnumerable<Type> knownTypes, int maxItemsInObjectGraph, bool ignoreExtensionDataObject, bool alwaysEmitTypeInformation)
78                 {
79                         if (type == null)
80                                 throw new ArgumentNullException ("type");
81                         if (rootName == null)
82                                 throw new ArgumentNullException ("rootName");
83                         if (maxItemsInObjectGraph < 0)
84                                 throw new ArgumentOutOfRangeException ("maxItemsInObjectGraph");
85
86                         this.type = type;
87
88                         var knownTypesFromAttributes = new List<Type> ();
89
90                         foreach (var attr in type.GetCustomAttributes (typeof (KnownTypeAttribute), false))
91                                 knownTypesFromAttributes.Add ((attr as KnownTypeAttribute).Type);
92
93                         if (knownTypes != null)
94                                 knownTypesFromAttributes.AddRange (knownTypes);
95
96                         known_types = new ReadOnlyCollection<Type> (knownTypesFromAttributes);
97
98                         root = rootName;
99                         max_items = maxItemsInObjectGraph;
100                         ignore_extension = ignoreExtensionDataObject;
101                         always_emit_type = alwaysEmitTypeInformation;
102                 }
103
104                 public DataContractJsonSerializer (Type type, IEnumerable<Type> knownTypes, int maxItemsInObjectGraph, bool ignoreExtensionDataObject, IDataContractSurrogate dataContractSurrogate, bool alwaysEmitTypeInformation)
105             : this (type, default_root_name, knownTypes, maxItemsInObjectGraph, ignoreExtensionDataObject, alwaysEmitTypeInformation)
106                 {
107         }
108
109                 public DataContractJsonSerializer (Type type, string rootName, IEnumerable<Type> knownTypes, int maxItemsInObjectGraph, bool ignoreExtensionDataObject, IDataContractSurrogate dataContractSurrogate, bool alwaysEmitTypeInformation)
110                         : this (type, rootName, knownTypes, maxItemsInObjectGraph, ignoreExtensionDataObject, alwaysEmitTypeInformation)
111                 {
112                         surrogate = dataContractSurrogate;
113                 }
114
115                 public DataContractJsonSerializer (Type type, XmlDictionaryString rootName, IEnumerable<Type> knownTypes, int maxItemsInObjectGraph, bool ignoreExtensionDataObject, IDataContractSurrogate dataContractSurrogate, bool alwaysEmitTypeInformation)
116                         : this (type, rootName != null ? rootName.Value : default_root_name, knownTypes, maxItemsInObjectGraph, ignoreExtensionDataObject, dataContractSurrogate, alwaysEmitTypeInformation)
117                 {
118                 }
119
120                 public DataContractJsonSerializer (Type type, DataContractJsonSerializerSettings settings)
121                         : this (type, settings.RootName, settings.KnownTypes, settings.MaxItemsInObjectGraph, settings.IgnoreExtensionDataObject,
122                                 settings.DataContractSurrogate, false)
123                 {
124                 }
125
126         #endregion
127
128         Type type;
129                 string root;
130                 ReadOnlyCollection<Type> known_types;
131                 int max_items;
132                 bool ignore_extension;
133                 bool always_emit_type;
134                 IDataContractSurrogate surrogate;
135
136                 [MonoTODO]
137                 public IDataContractSurrogate DataContractSurrogate {
138                         get { return surrogate; }
139                 }
140
141                 [MonoTODO]
142                 public bool IgnoreExtensionDataObject {
143                         get { return ignore_extension; }
144                 }
145                 public ReadOnlyCollection<Type> KnownTypes {
146                         get { return known_types; }
147                 }
148
149                 public int MaxItemsInObjectGraph {
150                         get { return max_items; }
151                 }
152
153                 public override bool IsStartObject (XmlReader reader)
154                 {
155                         if (reader == null)
156                                 throw new ArgumentNullException ("reader");
157                         reader.MoveToContent ();
158                         return reader.IsStartElement (root, String.Empty);
159                 }
160
161                 public override bool IsStartObject (XmlDictionaryReader reader)
162                 {
163                         return IsStartObject ((XmlReader) reader);
164                 }
165
166                 public override object ReadObject (Stream stream)
167                 {
168 #if NET_2_1
169                         var r = (JsonReader) JsonReaderWriterFactory.CreateJsonReader(stream, XmlDictionaryReaderQuotas.Max);
170                         r.LameSilverlightLiteralParser = true;
171                         return ReadObject(r);
172 #else
173                         return ReadObject (JsonReaderWriterFactory.CreateJsonReader (stream, new XmlDictionaryReaderQuotas ()));
174 #endif
175                 }
176
177                 public override object ReadObject (XmlDictionaryReader reader)
178                 {
179                         return ReadObject (reader, true);
180                 }
181
182                 public override object ReadObject (XmlReader reader)
183                 {
184                         return ReadObject (reader, true);
185                 }
186
187                 public override object ReadObject (XmlDictionaryReader reader, bool verifyObjectName)
188                 {
189                         return ReadObject ((XmlReader) reader, verifyObjectName);
190                 }
191
192                 public override object ReadObject (XmlReader reader, bool verifyObjectName)
193                 {
194                         if (reader == null)
195                                 throw new ArgumentNullException ("reader");
196                         try {
197                                 if (verifyObjectName && !IsStartObject (reader))
198                                         throw new SerializationException (String.Format ("Expected element was '{0}', but the actual input element was '{1}' in namespace '{2}'", root, reader.LocalName, reader.NamespaceURI));
199
200                                 return new JsonSerializationReader (this, reader, type, verifyObjectName).ReadRoot ();
201                         } catch (SerializationException) {
202                                 throw;
203                         } catch (InvalidDataContractException) {
204                                 throw;
205                         } catch (System.Reflection.TargetInvocationException ex) {
206                                 throw ex.InnerException;
207                         } catch (Exception ex) {
208                                 throw new SerializationException ("Deserialization has failed", ex);
209                         }
210                 }
211
212                 public override void WriteObject (Stream stream, object graph)
213                 {
214                         using (var xw = JsonReaderWriterFactory.CreateJsonWriter (stream))
215                                 WriteObject (xw, graph);
216                 }
217
218                 public override void WriteObject (XmlWriter writer, object graph)
219                 {
220                         try {
221                                 WriteStartObject (writer, graph);
222                                 WriteObjectContent (writer, graph);
223                                 WriteEndObject (writer);
224                         } catch (NotImplementedException) {
225                                 throw;
226                         } catch (InvalidDataContractException) {
227                                 throw;
228                         } catch (Exception ex) {
229                                 throw new SerializationException (String.Format ("There was an error during serialization for object of type {0}", graph != null ? graph.GetType () : null), ex);
230                         }
231                 }
232
233                 public override void WriteObject (XmlDictionaryWriter writer, object graph)
234                 {
235                         WriteObject ((XmlWriter) writer, graph);
236                 }
237
238                 public override void WriteStartObject (XmlDictionaryWriter writer, object graph)
239                 {
240                         WriteStartObject ((XmlWriter) writer, graph);
241                 }
242
243                 public override void WriteStartObject (XmlWriter writer, object graph)
244                 {
245                         if (writer == null)
246                                 throw new ArgumentNullException ("writer");
247                         writer.WriteStartElement (root);
248                 }
249
250                 public override void WriteObjectContent (XmlDictionaryWriter writer, object graph)
251                 {
252                         WriteObjectContent ((XmlWriter) writer, graph);
253                 }
254
255                 public override void WriteObjectContent (XmlWriter writer, object graph)
256                 {
257                         new JsonSerializationWriter (this, writer, type, always_emit_type).WriteObjectContent (graph, true, false);
258                 }
259
260                 public override void WriteEndObject (XmlDictionaryWriter writer)
261                 {
262                         WriteEndObject ((XmlWriter) writer);
263                 }
264
265                 public override void WriteEndObject (XmlWriter writer)
266                 {
267                         if (writer == null)
268                                 throw new ArgumentNullException ("writer");
269                         writer.WriteEndElement ();
270                 }
271
272                 [MonoTODO]
273                 public DateTimeFormat DateTimeFormat {
274                         get { throw new NotImplementedException (); }
275                 }
276
277                 [MonoTODO]
278                 public EmitTypeInformation EmitTypeInformation {
279                         get { throw new NotImplementedException (); }
280                 }
281
282                 [MonoTODO]
283                 public bool SerializeReadOnlyTypes {
284                         get { throw new NotImplementedException (); }
285                 }
286
287                 [MonoTODO]
288                 public bool UseSimpleDictionaryFormat {
289                         get { throw new NotImplementedException (); }
290                 }
291
292         }
293 }