PageRenderTime 58ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/mcs/class/System.Runtime.Serialization/System.Runtime.Serialization/SerializationMap.cs

https://bitbucket.org/steenlund/mono-2.6.7-for-amiga
C# | 1177 lines | 925 code | 164 blank | 88 comment | 208 complexity | 7c46c9d67814f659482d831f913c34d6 MD5 | raw file
Possible License(s): LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0, LGPL-2.1
  1. //
  2. // SerializationMap.cs
  3. //
  4. // Author:
  5. // Atsushi Enomoto <atsushi@ximian.com>
  6. // Ankit Jain <JAnkit@novell.com>
  7. // Duncan Mak (duncan@ximian.com)
  8. // Eyal Alaluf (eyala@mainsoft.com)
  9. //
  10. // Copyright (C) 2005 Novell, Inc. http://www.novell.com
  11. // Copyright (C) 2006 Novell, Inc. http://www.novell.com
  12. //
  13. // Permission is hereby granted, free of charge, to any person obtaining
  14. // a copy of this software and associated documentation files (the
  15. // "Software"), to deal in the Software without restriction, including
  16. // without limitation the rights to use, copy, modify, merge, publish,
  17. // distribute, sublicense, and/or sell copies of the Software, and to
  18. // permit persons to whom the Software is furnished to do so, subject to
  19. // the following conditions:
  20. //
  21. // The above copyright notice and this permission notice shall be
  22. // included in all copies or substantial portions of the Software.
  23. //
  24. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  25. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  26. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  27. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  28. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  29. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  30. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  31. //
  32. #if NET_2_0
  33. using System;
  34. using System.Collections;
  35. using System.Collections.Generic;
  36. using System.Collections.ObjectModel;
  37. using System.Linq;
  38. using System.Reflection;
  39. using System.Xml;
  40. using System.Xml.Schema;
  41. using System.Xml.Serialization;
  42. using QName = System.Xml.XmlQualifiedName;
  43. namespace System.Runtime.Serialization
  44. {
  45. /*
  46. XmlFormatter implementation design inference:
  47. type definitions:
  48. - No XML Schema types are directly used. There are some maps from
  49. xs:blahType to ms:blahType where the namespaceURI for prefix "ms" is
  50. "http://schemas.microsoft.com/2003/10/Serialization/" .
  51. serializable types:
  52. - An object being serialized 1) must be of type System.Object, or
  53. 2) must be null, or 3) must have either a [DataContract] attribute
  54. or a [Serializable] attribute to be serializable.
  55. - When the object is either of type System.Object or null, then the
  56. XML type is "anyType".
  57. - When the object is [Serializable], then the runtime-serialization
  58. compatible object graph is written.
  59. - Otherwise the serialization is based on contract attributes.
  60. ([Serializable] takes precedence).
  61. type derivation:
  62. - For type A to be serializable, the base type B of A must be
  63. serializable.
  64. - If a type which is [Serializable] and whose base type has a
  65. [DataContract], then for base type members [DataContract] is taken.
  66. - It is vice versa i.e. if the base type is [Serializable] and the
  67. derived type has a [DataContract], then [Serializable] takes place
  68. for base members.
  69. known type collection:
  70. - It internally manages mapping store keyed by contract QNames.
  71. KnownTypeCollection.Add() checks if the same QName contract already
  72. exists (and raises InvalidOperationException if required).
  73. */
  74. internal abstract class SerializationMap
  75. {
  76. public const BindingFlags AllInstanceFlags =
  77. BindingFlags.Public | BindingFlags.NonPublic |
  78. BindingFlags.Instance;
  79. public readonly KnownTypeCollection KnownTypes;
  80. public readonly Type RuntimeType;
  81. public bool IsReference; // new in 3.5 SP1
  82. public List<DataMemberInfo> Members;
  83. #if !NET_2_1
  84. XmlSchemaSet schema_set;
  85. #endif
  86. //FIXME FIXME
  87. Dictionary<Type, QName> qname_table = new Dictionary<Type, QName> ();
  88. protected SerializationMap (
  89. Type type, QName qname, KnownTypeCollection knownTypes)
  90. {
  91. KnownTypes = knownTypes;
  92. RuntimeType = type;
  93. if (qname.Namespace == null)
  94. qname = new QName (qname.Name,
  95. KnownTypeCollection.DefaultClrNamespaceBase + type.Namespace);
  96. XmlName = qname;
  97. Members = new List<DataMemberInfo> ();
  98. }
  99. public virtual bool OutputXsiType {
  100. get { return true; }
  101. }
  102. public QName XmlName { get; set; }
  103. public CollectionDataContractAttribute GetCollectionDataContractAttribute (Type type)
  104. {
  105. object [] atts = type.GetCustomAttributes (
  106. typeof (CollectionDataContractAttribute), false);
  107. return atts.Length == 0 ? null : (CollectionDataContractAttribute) atts [0];
  108. }
  109. public DataMemberAttribute GetDataMemberAttribute (
  110. MemberInfo mi)
  111. {
  112. object [] atts = mi.GetCustomAttributes (
  113. typeof (DataMemberAttribute), false);
  114. if (atts.Length == 0)
  115. return null;
  116. return (DataMemberAttribute) atts [0];
  117. }
  118. bool IsPrimitive (Type type)
  119. {
  120. return (Type.GetTypeCode (type) != TypeCode.Object || type == typeof (object));
  121. }
  122. #if !NET_2_1
  123. /* Returns the XmlSchemaType AND adds it to @schemas */
  124. public virtual XmlSchemaType GetSchemaType (XmlSchemaSet schemas, Dictionary<QName, XmlSchemaType> generated_schema_types)
  125. {
  126. if (IsPrimitive (RuntimeType))
  127. return null;
  128. if (generated_schema_types.ContainsKey (XmlName)) // Caching
  129. return generated_schema_types [XmlName] as XmlSchemaType;
  130. XmlSchemaComplexType complex_type = null;
  131. complex_type = new XmlSchemaComplexType ();
  132. complex_type.Name = XmlName.Name;
  133. generated_schema_types [XmlName] = complex_type;
  134. if (RuntimeType.BaseType == typeof (object)) {
  135. complex_type.Particle = GetSequence (schemas, generated_schema_types);
  136. } else {
  137. //Has a non-System.Object base class
  138. XmlSchemaComplexContentExtension extension = new XmlSchemaComplexContentExtension ();
  139. XmlSchemaComplexContent content = new XmlSchemaComplexContent ();
  140. complex_type.ContentModel = content;
  141. content.Content = extension;
  142. KnownTypes.Add (RuntimeType.BaseType);
  143. SerializationMap map = KnownTypes.FindUserMap (RuntimeType.BaseType);
  144. //FIXME: map == null ?
  145. map.GetSchemaType (schemas, generated_schema_types);
  146. extension.Particle = GetSequence (schemas, generated_schema_types);
  147. extension.BaseTypeName = GetQualifiedName (RuntimeType.BaseType);
  148. }
  149. XmlSchemaElement schemaElement = GetSchemaElement (XmlName, complex_type);
  150. XmlSchema schema = GetSchema (schemas, XmlName.Namespace);
  151. schema.Items.Add (complex_type);
  152. schema.Items.Add (schemaElement);
  153. schemas.Reprocess (schema);
  154. return complex_type;
  155. }
  156. /* Returns the <xs:sequence> for the data members */
  157. XmlSchemaSequence GetSequence (XmlSchemaSet schemas,
  158. Dictionary<QName, XmlSchemaType> generated_schema_types)
  159. {
  160. List<DataMemberInfo> members = GetMembers ();
  161. XmlSchema schema = GetSchema (schemas, XmlName.Namespace);
  162. XmlSchemaSequence sequence = new XmlSchemaSequence ();
  163. foreach (DataMemberInfo dmi in members) {
  164. // delegates are not supported.
  165. if (!dmi.MemberType.IsAbstract && typeof (System.Delegate).IsAssignableFrom (dmi.MemberType))
  166. continue;
  167. XmlSchemaElement element = new XmlSchemaElement ();
  168. element.Name = dmi.XmlName;
  169. KnownTypes.Add (dmi.MemberType);
  170. SerializationMap map = KnownTypes.FindUserMap (dmi.MemberType);
  171. if (map != null) {
  172. XmlSchemaType schema_type = map.GetSchemaType (schemas, generated_schema_types);
  173. if (schema_type is XmlSchemaComplexType)
  174. element.IsNillable = true;
  175. } else {
  176. //Primitive type
  177. if (dmi.MemberType == typeof (string))
  178. element.IsNillable = true;
  179. }
  180. element.MinOccurs = 0;
  181. element.SchemaTypeName = GetQualifiedName (dmi.MemberType);
  182. AddImport (schema, element.SchemaTypeName.Namespace);
  183. sequence.Items.Add (element);
  184. }
  185. schemas.Reprocess (schema);
  186. return sequence;
  187. }
  188. //FIXME: Replace with a dictionary ?
  189. void AddImport (XmlSchema schema, string ns)
  190. {
  191. if (ns == XmlSchema.Namespace || schema.TargetNamespace == ns)
  192. return;
  193. foreach (XmlSchemaObject o in schema.Includes) {
  194. XmlSchemaImport import = o as XmlSchemaImport;
  195. if (import == null)
  196. continue;
  197. if (import.Namespace == ns)
  198. return;
  199. }
  200. XmlSchemaImport imp = new XmlSchemaImport ();
  201. imp.Namespace = ns;
  202. schema.Includes.Add (imp);
  203. }
  204. #endif
  205. //Returns list of data members for this type ONLY
  206. public virtual List<DataMemberInfo> GetMembers ()
  207. {
  208. throw new NotImplementedException (String.Format ("Implement me for {0}", this));
  209. }
  210. #if !NET_2_1
  211. protected XmlSchemaElement GetSchemaElement (QName qname, XmlSchemaType schemaType)
  212. {
  213. XmlSchemaElement schemaElement = new XmlSchemaElement ();
  214. schemaElement.Name = qname.Name;
  215. schemaElement.SchemaTypeName = qname;
  216. if (schemaType is XmlSchemaComplexType)
  217. schemaElement.IsNillable = true;
  218. return schemaElement;
  219. }
  220. protected XmlSchema GetSchema (XmlSchemaSet schemas, string ns)
  221. {
  222. ICollection colln = schemas.Schemas (ns);
  223. if (colln.Count > 0) {
  224. if (colln.Count > 1)
  225. throw new Exception (String.Format (
  226. "More than 1 schema for namespace '{0}' found.", ns));
  227. foreach (object o in colln)
  228. //return colln [0]
  229. return (o as XmlSchema);
  230. }
  231. XmlSchema schema = new XmlSchema ();
  232. schema.TargetNamespace = ns;
  233. schema.ElementFormDefault = XmlSchemaForm.Qualified;
  234. schemas.Add (schema);
  235. return schema;
  236. }
  237. protected XmlQualifiedName GetQualifiedName (Type type)
  238. {
  239. if (qname_table.ContainsKey (type))
  240. return qname_table [type];
  241. QName qname = KnownTypes.GetQName (type);
  242. if (qname.Namespace == KnownTypeCollection.MSSimpleNamespace)
  243. qname = new QName (qname.Name, XmlSchema.Namespace);
  244. qname_table [type] = qname;
  245. return qname;
  246. }
  247. #endif
  248. public virtual void Serialize (object graph,
  249. XmlFormatterSerializer serializer)
  250. {
  251. string label = null;
  252. if (IsReference) {
  253. label = (string) serializer.References [graph];
  254. if (label != null) {
  255. serializer.Writer.WriteAttributeString ("z", "Ref", KnownTypeCollection.MSSimpleNamespace, label);
  256. return;
  257. }
  258. label = "i" + (serializer.References.Count + 1);
  259. serializer.References.Add (graph, label);
  260. }
  261. else if (serializer.SerializingObjects.Contains (graph))
  262. throw new SerializationException (String.Format ("Circular reference of an object in the object graph was found: '{0}' of type {1}", graph, graph.GetType ()));
  263. serializer.SerializingObjects.Add (graph);
  264. if (label != null)
  265. serializer.Writer.WriteAttributeString ("z", "Id", KnownTypeCollection.MSSimpleNamespace, label);
  266. SerializeNonReference (graph, serializer);
  267. serializer.SerializingObjects.Remove (graph);
  268. }
  269. public virtual void SerializeNonReference (object graph,
  270. XmlFormatterSerializer serializer)
  271. {
  272. foreach (DataMemberInfo dmi in Members) {
  273. FieldInfo fi = dmi.Member as FieldInfo;
  274. PropertyInfo pi = fi == null ?
  275. (PropertyInfo) dmi.Member : null;
  276. Type type = fi != null ?
  277. fi.FieldType : pi.PropertyType;
  278. object value = fi != null ?
  279. fi.GetValue (graph) :
  280. pi.GetValue (graph, null);
  281. serializer.WriteStartElement (dmi.XmlName, dmi.XmlRootNamespace, dmi.XmlNamespace);
  282. serializer.Serialize (type, value);
  283. serializer.WriteEndElement ();
  284. }
  285. }
  286. public virtual object DeserializeObject (XmlReader reader, XmlFormatterDeserializer deserializer)
  287. {
  288. bool isEmpty = reader.IsEmptyElement;
  289. reader.ReadStartElement ();
  290. reader.MoveToContent ();
  291. object res;
  292. if (isEmpty)
  293. res = DeserializeEmptyContent (reader, deserializer);
  294. else
  295. res = DeserializeContent (reader, deserializer);
  296. reader.MoveToContent ();
  297. if (!isEmpty && reader.NodeType == XmlNodeType.EndElement)
  298. reader.ReadEndElement ();
  299. else if (!isEmpty && reader.NodeType != XmlNodeType.None) {
  300. var li = reader as IXmlLineInfo;
  301. throw new SerializationException (String.Format ("Deserializing type '{3}'. Expecting state 'EndElement'. Encountered state '{0}' with name '{1}' with namespace '{2}'.{4}",
  302. reader.NodeType,
  303. reader.Name,
  304. reader.NamespaceURI,
  305. RuntimeType.FullName,
  306. li != null && li.HasLineInfo () ? String.Format (" {0}({1},{2})", reader.BaseURI, li.LineNumber, li.LinePosition) : String.Empty));
  307. }
  308. return res;
  309. }
  310. // This is sort of hack. The argument reader already moved ahead of
  311. // the actual empty element.It's just for historical consistency.
  312. public virtual object DeserializeEmptyContent (XmlReader reader,
  313. XmlFormatterDeserializer deserializer)
  314. {
  315. return DeserializeContent (reader, deserializer, true);
  316. }
  317. public virtual object DeserializeContent (XmlReader reader,
  318. XmlFormatterDeserializer deserializer)
  319. {
  320. return DeserializeContent (reader, deserializer, false);
  321. }
  322. object DeserializeContent (XmlReader reader,
  323. XmlFormatterDeserializer deserializer, bool empty)
  324. {
  325. object instance = FormatterServices.GetUninitializedObject (RuntimeType);
  326. int depth = reader.NodeType == XmlNodeType.None ? reader.Depth : reader.Depth - 1;
  327. bool [] filled = new bool [Members.Count];
  328. int memberInd = -1, ordered = -1;
  329. while (!empty && reader.NodeType == XmlNodeType.Element && reader.Depth > depth) {
  330. DataMemberInfo dmi = null;
  331. int i = 0;
  332. for (; i < Members.Count; i++) { // unordered
  333. if (Members [i].Order >= 0)
  334. break;
  335. if (reader.LocalName == Members [i].XmlName &&
  336. reader.NamespaceURI == Members [i].XmlRootNamespace) {
  337. memberInd = i;
  338. dmi = Members [i];
  339. break;
  340. }
  341. }
  342. for (i = Math.Max (i, ordered); i < Members.Count; i++) { // ordered
  343. if (dmi != null)
  344. break;
  345. if (reader.LocalName == Members [i].XmlName &&
  346. reader.NamespaceURI == Members [i].XmlRootNamespace) {
  347. memberInd = i;
  348. ordered = i;
  349. dmi = Members [i];
  350. break;
  351. }
  352. }
  353. if (dmi == null) {
  354. reader.Skip ();
  355. continue;
  356. }
  357. SetValue (dmi, instance, deserializer.Deserialize (dmi.MemberType, reader));
  358. filled [memberInd] = true;
  359. reader.MoveToContent ();
  360. }
  361. for (int i = 0; i < Members.Count; i++)
  362. if (!filled [i] && Members [i].IsRequired)
  363. throw MissingRequiredMember (Members [i], reader);
  364. return instance;
  365. }
  366. // For now it could be private.
  367. protected Exception MissingRequiredMember (DataMemberInfo dmi, XmlReader reader)
  368. {
  369. var li = reader as IXmlLineInfo;
  370. return new ArgumentException (String.Format ("Data contract member {0} for the type {1} is required, but missing in the input XML.{2}",
  371. new QName (dmi.XmlName, dmi.XmlNamespace),
  372. RuntimeType,
  373. li != null && li.HasLineInfo () ? String.Format (" {0}({1},{2})", reader.BaseURI, li.LineNumber, li.LinePosition) : null));
  374. }
  375. // For now it could be private.
  376. protected void SetValue (DataMemberInfo dmi, object obj, object value)
  377. {
  378. try {
  379. if (dmi.Member is PropertyInfo)
  380. ((PropertyInfo) dmi.Member).SetValue (obj, value, null);
  381. else
  382. ((FieldInfo) dmi.Member).SetValue (obj, value);
  383. } catch (Exception ex) {
  384. throw new InvalidOperationException (String.Format ("Failed to set value of type {0} for property {1}", value != null ? value.GetType () : null, dmi.Member), ex);
  385. }
  386. }
  387. protected DataMemberInfo CreateDataMemberInfo (DataMemberAttribute dma, MemberInfo mi, Type type)
  388. {
  389. KnownTypes.Add (type);
  390. QName qname = KnownTypes.GetQName (type);
  391. string rootNamespace = KnownTypes.GetQName (mi.DeclaringType).Namespace;
  392. if (KnownTypeCollection.GetPrimitiveTypeFromName (qname.Name) != null)
  393. return new DataMemberInfo (mi, dma, rootNamespace, null);
  394. else
  395. return new DataMemberInfo (mi, dma, rootNamespace, qname.Namespace);
  396. }
  397. }
  398. internal class XmlSerializableMap : SerializationMap
  399. {
  400. public XmlSerializableMap (Type type, QName qname, KnownTypeCollection knownTypes)
  401. : base (type, qname, knownTypes)
  402. {
  403. }
  404. public override void Serialize (object graph, XmlFormatterSerializer serializer)
  405. {
  406. IXmlSerializable ixs = graph as IXmlSerializable;
  407. if (ixs == null)
  408. //FIXME: Throw what exception here?
  409. throw new SerializationException ();
  410. ixs.WriteXml (serializer.Writer);
  411. }
  412. public override object DeserializeObject (XmlReader reader, XmlFormatterDeserializer deserializer)
  413. {
  414. IXmlSerializable ixs = (IXmlSerializable) FormatterServices.GetUninitializedObject (RuntimeType);
  415. ixs.ReadXml (reader);
  416. return ixs;
  417. }
  418. #if !NET_2_1
  419. // FIXME: verify return value sanity.
  420. public override XmlSchemaType GetSchemaType (XmlSchemaSet schemas, Dictionary<QName, XmlSchemaType> generated_schema_types)
  421. {
  422. return null;
  423. }
  424. #endif
  425. }
  426. internal class SharedContractMap : SerializationMap
  427. {
  428. public SharedContractMap (
  429. Type type, QName qname, KnownTypeCollection knownTypes)
  430. : base (type, qname, knownTypes)
  431. {
  432. }
  433. internal void Initialize ()
  434. {
  435. Type baseType = RuntimeType;
  436. List <DataMemberInfo> members = new List <DataMemberInfo> ();
  437. object [] atts = baseType.GetCustomAttributes (
  438. typeof (DataContractAttribute), false);
  439. IsReference = atts.Length > 0 ? (((DataContractAttribute) atts [0]).IsReference) : false;
  440. while (baseType != null) {
  441. QName bqname = KnownTypes.GetQName (baseType);
  442. members = GetMembers (baseType, bqname, true);
  443. members.Sort (DataMemberInfo.DataMemberInfoComparer.Instance);
  444. Members.InsertRange (0, members);
  445. members.Clear ();
  446. baseType = baseType.BaseType;
  447. }
  448. }
  449. List<DataMemberInfo> GetMembers (Type type, QName qname, bool declared_only)
  450. {
  451. List<DataMemberInfo> data_members = new List<DataMemberInfo> ();
  452. BindingFlags flags = AllInstanceFlags;
  453. if (declared_only)
  454. flags |= BindingFlags.DeclaredOnly;
  455. foreach (PropertyInfo pi in type.GetProperties (flags)) {
  456. DataMemberAttribute dma =
  457. GetDataMemberAttribute (pi);
  458. if (dma == null)
  459. continue;
  460. KnownTypes.TryRegister (pi.PropertyType);
  461. var map = KnownTypes.FindUserMap (pi.PropertyType);
  462. if (!pi.CanRead || (!pi.CanWrite && !(map is ICollectionTypeMap)))
  463. throw new InvalidDataContractException (String.Format (
  464. "DataMember property '{0}' on type '{1}' must have both getter and setter.", pi, pi.DeclaringType));
  465. data_members.Add (CreateDataMemberInfo (dma, pi, pi.PropertyType));
  466. }
  467. foreach (FieldInfo fi in type.GetFields (flags)) {
  468. DataMemberAttribute dma =
  469. GetDataMemberAttribute (fi);
  470. if (dma == null)
  471. continue;
  472. data_members.Add (CreateDataMemberInfo (dma, fi, fi.FieldType));
  473. }
  474. return data_members;
  475. }
  476. public override List<DataMemberInfo> GetMembers ()
  477. {
  478. return Members;
  479. }
  480. }
  481. internal class DefaultTypeMap : SerializationMap
  482. {
  483. public DefaultTypeMap (Type type, KnownTypeCollection knownTypes)
  484. : base (type, KnownTypeCollection.GetContractQName (type, null, null), knownTypes)
  485. {
  486. Members.AddRange (GetDefaultMembers ());
  487. }
  488. List<DataMemberInfo> GetDefaultMembers ()
  489. {
  490. var l = new List<DataMemberInfo> ();
  491. foreach (var mi in RuntimeType.GetMembers ()) {
  492. Type mt = null;
  493. FieldInfo fi = mi as FieldInfo;
  494. mt = fi == null ? null : fi.FieldType;
  495. PropertyInfo pi = mi as PropertyInfo;
  496. if (pi != null && pi.CanRead && pi.CanWrite && pi.GetIndexParameters ().Length == 0)
  497. mt = pi.PropertyType;
  498. if (mt == null)
  499. continue;
  500. if (mi.GetCustomAttributes (typeof (IgnoreDataMemberAttribute), false).Length != 0)
  501. continue;
  502. l.Add (new DataMemberInfo (mi, new DataMemberAttribute (), null, null));
  503. }
  504. l.Sort (DataMemberInfo.DataMemberInfoComparer.Instance);
  505. return l;
  506. }
  507. }
  508. // FIXME: it still needs to consider ItemName/KeyName/ValueName
  509. // (especially Dictionary collection is not likely considered yet.)
  510. internal class CollectionContractTypeMap : CollectionTypeMap
  511. {
  512. public CollectionContractTypeMap (
  513. Type type, CollectionDataContractAttribute a, Type elementType,
  514. QName qname, KnownTypeCollection knownTypes)
  515. : base (type, elementType, qname, knownTypes)
  516. {
  517. IsReference = a.IsReference;
  518. }
  519. internal override string CurrentNamespace {
  520. get { return XmlName.Namespace; }
  521. }
  522. }
  523. internal interface ICollectionTypeMap
  524. {
  525. }
  526. internal class CollectionTypeMap : SerializationMap, ICollectionTypeMap
  527. {
  528. Type element_type;
  529. internal QName element_qname;
  530. MethodInfo add_method;
  531. public CollectionTypeMap (
  532. Type type, Type elementType,
  533. QName qname, KnownTypeCollection knownTypes)
  534. : base (type, qname, knownTypes)
  535. {
  536. element_type = elementType;
  537. element_qname = KnownTypes.GetQName (element_type);
  538. var icoll = GetGenericCollectionInterface (RuntimeType);
  539. if (icoll != null) {
  540. if (RuntimeType.IsInterface) {
  541. add_method = RuntimeType.GetMethod ("Add", icoll.GetGenericArguments ());
  542. } else {
  543. var imap = RuntimeType.GetInterfaceMap (icoll);
  544. for (int i = 0; i < imap.InterfaceMethods.Length; i++)
  545. if (imap.InterfaceMethods [i].Name == "Add") {
  546. add_method = imap.TargetMethods [i];
  547. break;
  548. }
  549. if (add_method == null)
  550. add_method = type.GetMethod ("Add", icoll.GetGenericArguments ());
  551. }
  552. }
  553. }
  554. static Type GetGenericCollectionInterface (Type type)
  555. {
  556. foreach (var iface in type.GetInterfaces ())
  557. if (iface.IsGenericType && iface.GetGenericTypeDefinition () == typeof (ICollection<>))
  558. return iface;
  559. return null;
  560. }
  561. public override bool OutputXsiType {
  562. get { return false; }
  563. }
  564. internal virtual string CurrentNamespace {
  565. get {
  566. string ns = element_qname.Namespace;
  567. if (ns == KnownTypeCollection.MSSimpleNamespace)
  568. ns = KnownTypeCollection.MSArraysNamespace;
  569. return ns;
  570. }
  571. }
  572. public override void SerializeNonReference (object graph,
  573. XmlFormatterSerializer serializer)
  574. {
  575. foreach (object o in (IEnumerable) graph) {
  576. serializer.WriteStartElement (element_qname.Name, XmlName.Namespace, CurrentNamespace);
  577. serializer.Serialize (element_type, o);
  578. serializer.WriteEndElement ();
  579. }
  580. }
  581. object CreateInstance ()
  582. {
  583. if (RuntimeType.IsArray)
  584. return new ArrayList ();
  585. if (RuntimeType.IsInterface) {
  586. var icoll = GetGenericCollectionInterface (RuntimeType);
  587. if (icoll != null)
  588. return Activator.CreateInstance (typeof (List<>).MakeGenericType (RuntimeType.GetGenericArguments () [0])); // List<T>
  589. else // non-generic
  590. return new ArrayList ();
  591. }
  592. #if NET_2_1 // FIXME: is it fine?
  593. return Activator.CreateInstance (RuntimeType);
  594. #else
  595. return Activator.CreateInstance (RuntimeType, true);
  596. #endif
  597. }
  598. public override object DeserializeEmptyContent (XmlReader reader, XmlFormatterDeserializer deserializer)
  599. {
  600. return CreateInstance ();
  601. }
  602. public override object DeserializeContent (XmlReader reader, XmlFormatterDeserializer deserializer)
  603. {
  604. object instance = CreateInstance ();
  605. int depth = reader.NodeType == XmlNodeType.None ? reader.Depth : reader.Depth - 1;
  606. while (reader.NodeType == XmlNodeType.Element && reader.Depth > depth) {
  607. object elem = deserializer.Deserialize (element_type, reader);
  608. if (instance is IList)
  609. ((IList)instance).Add (elem);
  610. else if (add_method != null)
  611. add_method.Invoke (instance, new object [] {elem});
  612. else
  613. throw new NotImplementedException (String.Format ("Type {0} is not supported", RuntimeType));
  614. reader.MoveToContent ();
  615. }
  616. if (RuntimeType.IsArray)
  617. return ((ArrayList)instance).ToArray (element_type);
  618. return instance;
  619. }
  620. public override List<DataMemberInfo> GetMembers ()
  621. {
  622. //Shouldn't come here at all!
  623. throw new NotImplementedException ();
  624. }
  625. #if !NET_2_1
  626. public override XmlSchemaType GetSchemaType (XmlSchemaSet schemas, Dictionary<QName, XmlSchemaType> generated_schema_types)
  627. {
  628. if (generated_schema_types.ContainsKey (XmlName))
  629. return null;
  630. if (generated_schema_types.ContainsKey (XmlName))
  631. return generated_schema_types [XmlName];
  632. QName element_qname = GetQualifiedName (element_type);
  633. XmlSchemaComplexType complex_type = new XmlSchemaComplexType ();
  634. complex_type.Name = XmlName.Name;
  635. XmlSchemaSequence sequence = new XmlSchemaSequence ();
  636. XmlSchemaElement element = new XmlSchemaElement ();
  637. element.MinOccurs = 0;
  638. element.MaxOccursString = "unbounded";
  639. element.Name = element_qname.Name;
  640. KnownTypes.Add (element_type);
  641. SerializationMap map = KnownTypes.FindUserMap (element_type);
  642. if (map != null) {// non-primitive type
  643. map.GetSchemaType (schemas, generated_schema_types);
  644. element.IsNillable = true;
  645. }
  646. element.SchemaTypeName = element_qname;
  647. sequence.Items.Add (element);
  648. complex_type.Particle = sequence;
  649. XmlSchema schema = GetSchema (schemas, XmlName.Namespace);
  650. schema.Items.Add (complex_type);
  651. schema.Items.Add (GetSchemaElement (XmlName, complex_type));
  652. schemas.Reprocess (schema);
  653. generated_schema_types [XmlName] = complex_type;
  654. return complex_type;
  655. }
  656. #endif
  657. }
  658. internal class DictionaryTypeMap : SerializationMap, ICollectionTypeMap
  659. {
  660. Type key_type, value_type;
  661. QName dict_qname, item_qname, key_qname, value_qname;
  662. MethodInfo add_method;
  663. CollectionDataContractAttribute a;
  664. public DictionaryTypeMap (
  665. Type type, CollectionDataContractAttribute a, KnownTypeCollection knownTypes)
  666. : base (type, QName.Empty, knownTypes)
  667. {
  668. this.a = a;
  669. key_type = typeof (object);
  670. value_type = typeof (object);
  671. var idic = GetGenericDictionaryInterface (RuntimeType);
  672. if (idic != null) {
  673. var imap = RuntimeType.GetInterfaceMap (idic);
  674. for (int i = 0; i < imap.InterfaceMethods.Length; i++)
  675. if (imap.InterfaceMethods [i].Name == "Add") {
  676. add_method = imap.TargetMethods [i];
  677. break;
  678. }
  679. var argtypes = idic.GetGenericArguments();
  680. key_type = argtypes [0];
  681. value_type = argtypes [1];
  682. if (add_method == null)
  683. add_method = type.GetMethod ("Add", argtypes);
  684. }
  685. XmlName = GetDictionaryQName ();
  686. item_qname = GetItemQName ();
  687. key_qname = GetKeyQName ();
  688. value_qname = GetValueQName ();
  689. }
  690. static Type GetGenericDictionaryInterface (Type type)
  691. {
  692. foreach (var iface in type.GetInterfaces ())
  693. if (iface.IsGenericType && iface.GetGenericTypeDefinition () == typeof (IDictionary<,>))
  694. return iface;
  695. return null;
  696. }
  697. string ContractNamespace {
  698. get { return a != null && !String.IsNullOrEmpty (a.Namespace) ? a.Namespace : KnownTypeCollection.MSArraysNamespace; }
  699. }
  700. public Type KeyType { get { return key_type; } }
  701. public Type ValueType { get { return value_type; } }
  702. static readonly QName kvpair_key_qname = new QName ("Key", KnownTypeCollection.MSArraysNamespace);
  703. static readonly QName kvpair_value_qname = new QName ("Value", KnownTypeCollection.MSArraysNamespace);
  704. internal virtual QName GetDictionaryQName ()
  705. {
  706. if (a != null && !String.IsNullOrEmpty (a.Name))
  707. return new QName (a.Name, ContractNamespace);
  708. return new QName ("ArrayOf" + GetItemQName ().Name, KnownTypeCollection.MSArraysNamespace);
  709. }
  710. internal virtual QName GetItemQName ()
  711. {
  712. if (a != null && !String.IsNullOrEmpty (a.ItemName))
  713. return new QName (a.ItemName, ContractNamespace);
  714. return new QName ("KeyValueOf" + KnownTypes.GetQName (key_type).Name + KnownTypes.GetQName (value_type).Name, KnownTypeCollection.MSArraysNamespace);
  715. }
  716. internal virtual QName GetKeyQName ()
  717. {
  718. if (a != null && !String.IsNullOrEmpty (a.KeyName))
  719. return new QName (a.KeyName, ContractNamespace);
  720. return kvpair_key_qname;
  721. }
  722. internal virtual QName GetValueQName ()
  723. {
  724. if (a != null && !String.IsNullOrEmpty (a.ValueName))
  725. return new QName (a.ValueName, ContractNamespace);
  726. return kvpair_value_qname;
  727. }
  728. internal virtual string CurrentNamespace {
  729. get {
  730. string ns = item_qname.Namespace;
  731. if (ns == KnownTypeCollection.MSSimpleNamespace)
  732. ns = KnownTypeCollection.MSArraysNamespace;
  733. return ns;
  734. }
  735. }
  736. Type pair_type;
  737. PropertyInfo pair_key_property, pair_value_property;
  738. public override void SerializeNonReference (object graph,
  739. XmlFormatterSerializer serializer)
  740. {
  741. if (add_method != null) { // generic
  742. if (pair_type == null) {
  743. pair_type = typeof (KeyValuePair<,>).MakeGenericType (add_method.DeclaringType.GetGenericArguments ());
  744. pair_key_property = pair_type.GetProperty ("Key");
  745. pair_value_property = pair_type.GetProperty ("Value");
  746. }
  747. foreach (object p in (IEnumerable) graph) {
  748. serializer.WriteStartElement (item_qname.Name, item_qname.Namespace, CurrentNamespace);
  749. serializer.WriteStartElement (key_qname.Name, key_qname.Namespace, CurrentNamespace);
  750. serializer.Serialize (pair_key_property.PropertyType, pair_key_property.GetValue (p, null));
  751. serializer.WriteEndElement ();
  752. serializer.WriteStartElement (value_qname.Name, value_qname.Namespace, CurrentNamespace);
  753. serializer.Serialize (pair_value_property.PropertyType, pair_value_property.GetValue (p, null));
  754. serializer.WriteEndElement ();
  755. serializer.WriteEndElement ();
  756. }
  757. } else { // non-generic
  758. foreach (DictionaryEntry p in (IEnumerable) graph) {
  759. serializer.WriteStartElement (item_qname.Name, item_qname.Namespace, CurrentNamespace);
  760. serializer.WriteStartElement (key_qname.Name, key_qname.Namespace, CurrentNamespace);
  761. serializer.Serialize (key_type, p.Key);
  762. serializer.WriteEndElement ();
  763. serializer.WriteStartElement (value_qname.Name, value_qname.Namespace, CurrentNamespace);
  764. serializer.Serialize (value_type, p.Value);
  765. serializer.WriteEndElement ();
  766. serializer.WriteEndElement ();
  767. }
  768. }
  769. }
  770. object CreateInstance ()
  771. {
  772. if (RuntimeType.IsInterface) {
  773. if (RuntimeType.IsGenericType && Array.IndexOf (RuntimeType.GetGenericTypeDefinition ().GetInterfaces (), typeof (IDictionary<,>)) >= 0) {
  774. var gargs = RuntimeType.GetGenericArguments ();
  775. return Activator.CreateInstance (typeof (Dictionary<,>).MakeGenericType (gargs [0], gargs [1])); // Dictionary<T>
  776. }
  777. else // non-generic
  778. return new Hashtable ();
  779. }
  780. #if NET_2_1 // FIXME: is it fine?
  781. return Activator.CreateInstance (RuntimeType);
  782. #else
  783. return Activator.CreateInstance (RuntimeType, true);
  784. #endif
  785. }
  786. public override object DeserializeEmptyContent (XmlReader reader, XmlFormatterDeserializer deserializer)
  787. {
  788. return DeserializeContent (reader, deserializer);
  789. }
  790. public override object DeserializeContent(XmlReader reader, XmlFormatterDeserializer deserializer)
  791. {
  792. object instance = CreateInstance ();
  793. int depth = reader.NodeType == XmlNodeType.None ? reader.Depth : reader.Depth - 1;
  794. while (reader.NodeType == XmlNodeType.Element && reader.Depth > depth) {
  795. if (reader.IsEmptyElement)
  796. throw new XmlException (String.Format ("Unexpected empty element for dictionary entry: name {0}", reader.Name));
  797. // FIXME: sloppy parsing
  798. reader.ReadStartElement ();// item_qname.Name, item_qname.Namespace);
  799. reader.MoveToContent ();
  800. object key = deserializer.Deserialize (key_type, reader);
  801. reader.MoveToContent ();
  802. object val = deserializer.Deserialize (value_type, reader);
  803. reader.ReadEndElement (); // of pair
  804. if (instance is IDictionary)
  805. ((IDictionary)instance).Add (key, val);
  806. else if (add_method != null)
  807. add_method.Invoke (instance, new object [] {key, val});
  808. else
  809. throw new NotImplementedException (String.Format ("Type {0} is not supported", RuntimeType));
  810. }
  811. return instance;
  812. }
  813. public override List<DataMemberInfo> GetMembers ()
  814. {
  815. //Shouldn't come here at all!
  816. throw new NotImplementedException ();
  817. }
  818. #if !NET_2_1
  819. public override XmlSchemaType GetSchemaType (XmlSchemaSet schemas, Dictionary<QName, XmlSchemaType> generated_schema_types)
  820. {
  821. throw new NotImplementedException ();
  822. }
  823. #endif
  824. }
  825. internal class SharedTypeMap : SerializationMap
  826. {
  827. public SharedTypeMap (
  828. Type type, QName qname, KnownTypeCollection knownTypes)
  829. : base (type, qname, knownTypes)
  830. {
  831. Members = GetMembers (type, XmlName, false);
  832. }
  833. List<DataMemberInfo> GetMembers (Type type, QName qname, bool declared_only)
  834. {
  835. List<DataMemberInfo> data_members = new List<DataMemberInfo> ();
  836. BindingFlags flags = AllInstanceFlags;
  837. if (declared_only)
  838. flags |= BindingFlags.DeclaredOnly;
  839. foreach (FieldInfo fi in type.GetFields (flags)) {
  840. if (fi.GetCustomAttributes (
  841. typeof (NonSerializedAttribute),
  842. false).Length > 0)
  843. continue;
  844. if (fi.IsInitOnly)
  845. throw new InvalidDataContractException (String.Format ("DataMember field {0} must not be read-only.", fi));
  846. DataMemberAttribute dma = new DataMemberAttribute ();
  847. data_members.Add (CreateDataMemberInfo (dma, fi, fi.FieldType));
  848. }
  849. data_members.Sort (DataMemberInfo.DataMemberInfoComparer.Instance); // alphabetic order.
  850. return data_members;
  851. }
  852. // Does this make sense? I doubt.
  853. public override List<DataMemberInfo> GetMembers ()
  854. {
  855. return Members;
  856. //return GetMembers (RuntimeType, XmlName, true);
  857. }
  858. }
  859. internal class EnumMap : SerializationMap
  860. {
  861. List<EnumMemberInfo> enum_members;
  862. bool flag_attr;
  863. public EnumMap (
  864. Type type, QName qname, KnownTypeCollection knownTypes)
  865. : base (type, qname, knownTypes)
  866. {
  867. bool has_dc = false;
  868. object [] atts = RuntimeType.GetCustomAttributes (
  869. typeof (DataContractAttribute), false);
  870. if (atts.Length != 0)
  871. has_dc = true;
  872. flag_attr = type.GetCustomAttributes (typeof (FlagsAttribute), false).Length > 0;
  873. enum_members = new List<EnumMemberInfo> ();
  874. BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Static;
  875. foreach (FieldInfo fi in RuntimeType.GetFields (flags)) {
  876. string name = fi.Name;
  877. if (has_dc) {
  878. EnumMemberAttribute ema =
  879. GetEnumMemberAttribute (fi);
  880. if (ema == null)
  881. continue;
  882. if (ema.Value != null)
  883. name = ema.Value;
  884. }
  885. enum_members.Add (new EnumMemberInfo (name, fi.GetValue (null)));
  886. }
  887. }
  888. private EnumMemberAttribute GetEnumMemberAttribute (
  889. MemberInfo mi)
  890. {
  891. object [] atts = mi.GetCustomAttributes (
  892. typeof (EnumMemberAttribute), false);
  893. if (atts.Length == 0)
  894. return null;
  895. return (EnumMemberAttribute) atts [0];
  896. }
  897. #if !NET_2_1
  898. public override XmlSchemaType GetSchemaType (XmlSchemaSet schemas, Dictionary<QName, XmlSchemaType> generated_schema_types)
  899. {
  900. if (generated_schema_types.ContainsKey (XmlName))
  901. return generated_schema_types [XmlName];
  902. XmlSchemaSimpleType simpleType = new XmlSchemaSimpleType ();
  903. simpleType.Name = XmlName.Name;
  904. XmlSchemaSimpleTypeRestriction simpleRestriction = new XmlSchemaSimpleTypeRestriction ();
  905. simpleType.Content = simpleRestriction;
  906. simpleRestriction.BaseTypeName = new XmlQualifiedName ("string", XmlSchema.Namespace);
  907. foreach (EnumMemberInfo emi in enum_members) {
  908. XmlSchemaEnumerationFacet e = new XmlSchemaEnumerationFacet ();
  909. e.Value = emi.XmlName;
  910. simpleRestriction.Facets.Add (e);
  911. }
  912. generated_schema_types [XmlName] = simpleType;
  913. XmlSchema schema = GetSchema (schemas, XmlName.Namespace);
  914. XmlSchemaElement element = GetSchemaElement (XmlName, simpleType);
  915. element.IsNillable = true;
  916. schema.Items.Add (simpleType);
  917. schema.Items.Add (element);
  918. return simpleType;
  919. }
  920. #endif
  921. public override void Serialize (object graph,
  922. XmlFormatterSerializer serializer)
  923. {
  924. foreach (EnumMemberInfo emi in enum_members) {
  925. if (Enum.Equals (emi.Value, graph)) {
  926. serializer.Writer.WriteString (emi.XmlName);
  927. return;
  928. }
  929. }
  930. throw new SerializationException (String.Format (
  931. "Enum value '{0}' is invalid for type '{1}' and cannot be serialized.", graph, RuntimeType));
  932. }
  933. public override object DeserializeEmptyContent (XmlReader reader,
  934. XmlFormatterDeserializer deserializer)
  935. {
  936. if (!flag_attr)
  937. throw new SerializationException (String.Format ("Enum value '' is invalid for type '{0}' and cannot be deserialized.", RuntimeType));
  938. return Enum.ToObject (RuntimeType, 0);
  939. }
  940. public override object DeserializeContent (XmlReader reader,
  941. XmlFormatterDeserializer deserializer)
  942. {
  943. string value = reader.NodeType != XmlNodeType.Text ? String.Empty : reader.ReadContentAsString ();
  944. if (value != String.Empty) {
  945. foreach (EnumMemberInfo emi in enum_members)
  946. if (emi.XmlName == value)
  947. return emi.Value;
  948. }
  949. if (!flag_attr)
  950. throw new SerializationException (String.Format ("Enum value '{0}' is invalid for type '{1}' and cannot be deserialized.", value, RuntimeType));
  951. return Enum.ToObject (RuntimeType, 0);
  952. }
  953. }
  954. internal struct EnumMemberInfo
  955. {
  956. public readonly string XmlName;
  957. public readonly object Value;
  958. public EnumMemberInfo (string name, object value)
  959. {
  960. XmlName = name;
  961. Value = value;
  962. }
  963. }
  964. internal class DataMemberInfo //: KeyValuePair<int, MemberInfo>
  965. {
  966. public readonly int Order;
  967. public readonly bool IsRequired;
  968. public readonly string XmlName;
  969. public readonly MemberInfo Member;
  970. public readonly string XmlNamespace;
  971. public readonly string XmlRootNamespace;
  972. public readonly Type MemberType;
  973. public DataMemberInfo (MemberInfo member, DataMemberAttribute dma, string rootNamespce, string ns)
  974. {
  975. if (dma == null)
  976. throw new ArgumentNullException ("dma");
  977. Order = dma.Order;
  978. Member = member;
  979. IsRequired = dma.IsRequired;
  980. XmlName = dma.Name != null ? dma.Name : member.Name;
  981. XmlNamespace = ns;
  982. XmlRootNamespace = rootNamespce;
  983. if (Member is FieldInfo)
  984. MemberType = ((FieldInfo) Member).FieldType;
  985. else
  986. MemberType = ((PropertyInfo) Member).PropertyType;
  987. }
  988. public class DataMemberInfoComparer : IComparer<DataMemberInfo>
  989. , IComparer // see bug #76361
  990. {
  991. public static readonly DataMemberInfoComparer Instance
  992. = new DataMemberInfoComparer ();
  993. private DataMemberInfoComparer () {}
  994. public int Compare (object o1, object o2)
  995. {
  996. return Compare ((DataMemberInfo) o1,
  997. (DataMemberInfo) o2);
  998. }
  999. public int Compare (DataMemberInfo d1, DataMemberInfo d2)
  1000. {
  1001. if (d1.Order == d2.Order)
  1002. return String.CompareOrdinal (d1.XmlName, d2.XmlName);
  1003. return d1.Order - d2.Order;
  1004. }
  1005. }
  1006. }
  1007. }
  1008. #endif