PageRenderTime 50ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/mcs/class/System.ServiceModel.Web/System.Runtime.Serialization.Json/TypeMap.cs

https://bitbucket.org/steenlund/mono-2.6.7-for-amiga
C# | 280 lines | 215 code | 37 blank | 28 comment | 59 complexity | cf787e970819939247c1f269db8b7b70 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. // TypeMap.cs
  3. //
  4. // Author:
  5. // Atsushi Enomoto <atsushi@ximian.com>
  6. //
  7. // Copyright (C) 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.Runtime.Serialization;
  37. using System.Text;
  38. using System.Xml;
  39. namespace System.Runtime.Serialization.Json
  40. {
  41. class TypeMap
  42. {
  43. static bool IsInvalidNCName (string name)
  44. {
  45. if (name == null || name.Length == 0)
  46. return true;
  47. try {
  48. XmlConvert.VerifyNCName (name);
  49. } catch (XmlException) {
  50. return true;
  51. }
  52. return false;
  53. }
  54. public static TypeMap CreateTypeMap (Type type)
  55. {
  56. object [] atts = type.GetCustomAttributes (typeof (DataContractAttribute), true);
  57. if (atts.Length == 1)
  58. return CreateTypeMap (type, (DataContractAttribute) atts [0]);
  59. atts = type.GetCustomAttributes (typeof (SerializableAttribute), false);
  60. if (atts.Length == 1)
  61. return CreateTypeMap (type, null);
  62. if (IsPrimitiveType (type))
  63. return null;
  64. return CreateDefaultTypeMap (type);
  65. }
  66. static bool IsPrimitiveType (Type type)
  67. {
  68. if (type.IsEnum)
  69. return true;
  70. if (Type.GetTypeCode (type) != TypeCode.Object)
  71. return true; // FIXME: it is likely hacky
  72. return false;
  73. }
  74. static TypeMap CreateDefaultTypeMap (Type type)
  75. {
  76. var l = new List<TypeMapMember> ();
  77. foreach (var fi in type.GetFields ())
  78. l.Add (new TypeMapField (fi, null));
  79. foreach (var pi in type.GetProperties ())
  80. if (pi.CanRead && pi.CanWrite)
  81. l.Add (new TypeMapProperty (pi, null));
  82. l.Sort ((x, y) => x.Order != y.Order ? x.Order - y.Order : String.Compare (x.Name, y.Name, StringComparison.Ordinal));
  83. return new TypeMap (type, null, l.ToArray ());
  84. }
  85. static bool IsCollection (Type type)
  86. {
  87. if (type.GetInterface ("System.Collections.IList", false) != null)
  88. return true;
  89. if (type.GetInterface ("System.Collections.Generic.IList`1", false) != null)
  90. return true;
  91. if (type.GetInterface ("System.Collections.Generic.ICollection`1", false) != null)
  92. return true;
  93. return false;
  94. }
  95. static TypeMap CreateTypeMap (Type type, DataContractAttribute dca)
  96. {
  97. if (dca != null && dca.Name != null && IsInvalidNCName (dca.Name))
  98. throw new InvalidDataContractException (String.Format ("DataContractAttribute for type '{0}' has an invalid name", type));
  99. List<TypeMapMember> members = new List<TypeMapMember> ();
  100. foreach (FieldInfo fi in type.GetFields (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) {
  101. if (dca != null) {
  102. object [] atts = fi.GetCustomAttributes (typeof (DataMemberAttribute), true);
  103. if (atts.Length == 0)
  104. continue;
  105. DataMemberAttribute dma = (DataMemberAttribute) atts [0];
  106. members.Add (new TypeMapField (fi, dma));
  107. } else {
  108. if (fi.GetCustomAttributes (typeof (IgnoreDataMemberAttribute), false).Length > 0)
  109. continue;
  110. members.Add (new TypeMapField (fi, null));
  111. }
  112. }
  113. if (dca != null) {
  114. foreach (PropertyInfo pi in type.GetProperties (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) {
  115. object [] atts = pi.GetCustomAttributes (typeof (DataMemberAttribute), true);
  116. if (atts.Length == 0)
  117. continue;
  118. if (pi.GetIndexParameters ().Length > 0)
  119. continue;
  120. if (IsCollection (pi.PropertyType)) {
  121. if (!pi.CanRead)
  122. throw new InvalidDataContractException (String.Format ("Property {0} must have a getter", pi));
  123. }
  124. else if (!pi.CanRead || !pi.CanWrite)
  125. throw new InvalidDataContractException (String.Format ("Non-collection property {0} must have both getter and setter", pi));
  126. DataMemberAttribute dma = (DataMemberAttribute) atts [0];
  127. members.Add (new TypeMapProperty (pi, dma));
  128. }
  129. }
  130. members.Sort (delegate (TypeMapMember m1, TypeMapMember m2) { return m1.Order != m2.Order ? m1.Order - m2.Order : String.CompareOrdinal (m1.Name, m2.Name); });
  131. return new TypeMap (type, dca == null ? null : dca.Name, members.ToArray ());
  132. }
  133. Type type;
  134. string element;
  135. TypeMapMember [] members;
  136. public TypeMap (Type type, string element, TypeMapMember [] orderedMembers)
  137. {
  138. this.type = type;
  139. this.element = element;
  140. this.members = orderedMembers;
  141. }
  142. public void Serialize (JsonSerializationWriter outputter, object graph)
  143. {
  144. foreach (TypeMapMember member in members) {
  145. object memberObj = member.GetMemberOf (graph);
  146. // FIXME: consider EmitDefaultValue
  147. outputter.Writer.WriteStartElement (member.Name);
  148. outputter.WriteObjectContent (memberObj, false, false);
  149. outputter.Writer.WriteEndElement ();
  150. }
  151. }
  152. public object Deserialize (JsonSerializationReader jsr)
  153. {
  154. XmlReader reader = jsr.Reader;
  155. object ret = FormatterServices.GetUninitializedObject (type);
  156. Dictionary<TypeMapMember,bool> filled = new Dictionary<TypeMapMember,bool> ();
  157. reader.ReadStartElement ();
  158. for (reader.MoveToContent (); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ()) {
  159. bool consumed = false;
  160. for (int i = 0; i < members.Length; i++) {
  161. TypeMapMember mm = members [i];
  162. if (mm.Name == reader.LocalName && reader.NamespaceURI == String.Empty) {
  163. if (filled.ContainsKey (mm))
  164. throw new SerializationException (String.Format ("Object content '{0}' for '{1}' already appeared in the reader", reader.LocalName, type));
  165. mm.SetMemberValue (ret, jsr.ReadObject (mm.Type));
  166. filled [mm] = true;
  167. consumed = true;
  168. break;
  169. }
  170. }
  171. if (!consumed)
  172. reader.Skip ();
  173. }
  174. reader.ReadEndElement ();
  175. return ret;
  176. }
  177. }
  178. abstract class TypeMapMember
  179. {
  180. MemberInfo mi;
  181. DataMemberAttribute dma;
  182. protected TypeMapMember (MemberInfo mi, DataMemberAttribute dma)
  183. {
  184. this.mi = mi;
  185. this.dma = dma;
  186. }
  187. public string Name {
  188. get { return dma == null ? mi.Name : dma.Name ?? mi.Name; }
  189. }
  190. public bool EmitDefaultValue {
  191. get { return dma != null && dma.EmitDefaultValue; }
  192. }
  193. public bool IsRequired {
  194. get { return dma != null && dma.IsRequired; }
  195. }
  196. public int Order {
  197. get { return dma != null ? dma.Order : -1; }
  198. }
  199. public abstract Type Type { get; }
  200. public abstract object GetMemberOf (object owner);
  201. public abstract void SetMemberValue (object owner, object value);
  202. }
  203. class TypeMapField : TypeMapMember
  204. {
  205. FieldInfo field;
  206. public TypeMapField (FieldInfo fi, DataMemberAttribute dma)
  207. : base (fi, dma)
  208. {
  209. this.field = fi;
  210. }
  211. public override Type Type {
  212. get { return field.FieldType; }
  213. }
  214. public override object GetMemberOf (object owner)
  215. {
  216. return field.GetValue (owner);
  217. }
  218. public override void SetMemberValue (object owner, object value)
  219. {
  220. field.SetValue (owner, value);
  221. }
  222. }
  223. class TypeMapProperty : TypeMapMember
  224. {
  225. PropertyInfo property;
  226. public TypeMapProperty (PropertyInfo pi, DataMemberAttribute dma)
  227. : base (pi, dma)
  228. {
  229. this.property = pi;
  230. }
  231. public override Type Type {
  232. get { return property.PropertyType; }
  233. }
  234. public override object GetMemberOf (object owner)
  235. {
  236. return property.GetValue (owner, null);
  237. }
  238. public override void SetMemberValue (object owner, object value)
  239. {
  240. property.SetValue (owner, value, null);
  241. }
  242. }
  243. }