XmlReflectionImporter.cs 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068
  1. //
  2. // System.Xml.Serialization.XmlReflectionImporter
  3. //
  4. // Author:
  5. // Tim Coleman ([email protected])
  6. // Erik LeBel ([email protected])
  7. // Lluis Sanchez Gual ([email protected])
  8. //
  9. // Copyright (C) Tim Coleman, 2002
  10. // (C) 2003 Erik LeBel
  11. //
  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. using System.Collections;
  33. using System.Globalization;
  34. using System.Reflection;
  35. using System.Xml.Schema;
  36. namespace System.Xml.Serialization {
  37. public class XmlReflectionImporter {
  38. string initialDefaultNamespace;
  39. XmlAttributeOverrides attributeOverrides;
  40. ArrayList includedTypes;
  41. ReflectionHelper helper = new ReflectionHelper();
  42. int arrayChoiceCount = 1;
  43. ArrayList relatedMaps = new ArrayList ();
  44. bool allowPrivateTypes = false;
  45. static readonly string errSimple = "Cannot serialize object of type '{0}'. Base " +
  46. "type '{1}' has simpleContent and can be only extended by adding XmlAttribute " +
  47. "elements. Please consider changing XmlText member of the base class to string array";
  48. static readonly string errSimple2 = "Cannot serialize object of type '{0}'. " +
  49. "Consider changing type of XmlText member '{1}' from '{2}' to string or string array";
  50. #region Constructors
  51. public XmlReflectionImporter ()
  52. : this (null, null)
  53. {
  54. }
  55. public XmlReflectionImporter (string defaultNamespace)
  56. : this (null, defaultNamespace)
  57. {
  58. }
  59. public XmlReflectionImporter (XmlAttributeOverrides attributeOverrides)
  60. : this (attributeOverrides, null)
  61. {
  62. }
  63. public XmlReflectionImporter (XmlAttributeOverrides attributeOverrides, string defaultNamespace)
  64. {
  65. if (defaultNamespace == null)
  66. this.initialDefaultNamespace = String.Empty;
  67. else
  68. this.initialDefaultNamespace = defaultNamespace;
  69. if (attributeOverrides == null)
  70. this.attributeOverrides = new XmlAttributeOverrides();
  71. else
  72. this.attributeOverrides = attributeOverrides;
  73. }
  74. /* void Reset ()
  75. {
  76. helper = new ReflectionHelper();
  77. arrayChoiceCount = 1;
  78. }
  79. */
  80. internal bool AllowPrivateTypes
  81. {
  82. get { return allowPrivateTypes; }
  83. set { allowPrivateTypes = value; }
  84. }
  85. #endregion // Constructors
  86. #region Methods
  87. public XmlMembersMapping ImportMembersMapping (string elementName,
  88. string ns,
  89. XmlReflectionMember [] members,
  90. bool hasWrapperElement)
  91. {
  92. // Reset (); Disabled. See ChangeLog
  93. XmlMemberMapping[] mapping = new XmlMemberMapping[members.Length];
  94. for (int n=0; n<members.Length; n++)
  95. {
  96. XmlTypeMapMember mapMem = CreateMapMember (null, members[n], ns);
  97. mapping[n] = new XmlMemberMapping (members[n].MemberName, ns, mapMem, false);
  98. }
  99. elementName = XmlConvert.EncodeLocalName (elementName);
  100. XmlMembersMapping mps = new XmlMembersMapping (elementName, ns, hasWrapperElement, false, mapping);
  101. mps.RelatedMaps = relatedMaps;
  102. mps.Format = SerializationFormat.Literal;
  103. Type[] extraTypes = includedTypes != null ? (Type[])includedTypes.ToArray(typeof(Type)) : null;
  104. mps.Source = new MembersSerializationSource (elementName, hasWrapperElement, members, false, true, ns, extraTypes);
  105. if (allowPrivateTypes) mps.Source.CanBeGenerated = false;
  106. return mps;
  107. }
  108. #if NET_2_0
  109. [MonoTODO]
  110. public XmlMembersMapping ImportMembersMapping (string elementName,
  111. string ns,
  112. XmlReflectionMember[] members,
  113. bool hasWrapperElement,
  114. bool rpc)
  115. {
  116. throw new NotImplementedException ();
  117. }
  118. [MonoTODO]
  119. public XmlMembersMapping ImportMembersMapping (string elementName,
  120. string ns,
  121. XmlReflectionMember[] members,
  122. bool hasWrapperElement,
  123. bool rpc,
  124. bool openModel)
  125. {
  126. throw new NotImplementedException ();
  127. }
  128. #endif
  129. public XmlTypeMapping ImportTypeMapping (Type type)
  130. {
  131. return ImportTypeMapping (type, null, null);
  132. }
  133. public XmlTypeMapping ImportTypeMapping (Type type, string defaultNamespace)
  134. {
  135. return ImportTypeMapping (type, null, defaultNamespace);
  136. }
  137. public XmlTypeMapping ImportTypeMapping (Type type, XmlRootAttribute group)
  138. {
  139. return ImportTypeMapping (type, group, null);
  140. }
  141. public XmlTypeMapping ImportTypeMapping (Type type, XmlRootAttribute root, string defaultNamespace)
  142. {
  143. if (type == null)
  144. throw new ArgumentNullException ("type");
  145. if (type == typeof (void))
  146. throw new NotSupportedException ("The type " + type.FullName + " may not be serialized.");
  147. return ImportTypeMapping (TypeTranslator.GetTypeData (type), root,
  148. defaultNamespace);
  149. }
  150. internal XmlTypeMapping ImportTypeMapping (TypeData typeData, string defaultNamespace)
  151. {
  152. return ImportTypeMapping (typeData, (XmlRootAttribute) null,
  153. defaultNamespace);
  154. }
  155. private XmlTypeMapping ImportTypeMapping (TypeData typeData, XmlRootAttribute root, string defaultNamespace)
  156. {
  157. if (typeData == null)
  158. throw new ArgumentNullException ("typeData");
  159. if (typeData.Type == null)
  160. throw new ArgumentException ("Specified TypeData instance does not have Type set.");
  161. if (defaultNamespace == null) defaultNamespace = initialDefaultNamespace;
  162. if (defaultNamespace == null) defaultNamespace = string.Empty;
  163. try {
  164. XmlTypeMapping map;
  165. switch (typeData.SchemaType) {
  166. case SchemaTypes.Class: map = ImportClassMapping (typeData, root, defaultNamespace); break;
  167. case SchemaTypes.Array: map = ImportListMapping (typeData, root, defaultNamespace, null, 0); break;
  168. case SchemaTypes.XmlNode: map = ImportXmlNodeMapping (typeData, root, defaultNamespace); break;
  169. case SchemaTypes.Primitive: map = ImportPrimitiveMapping (typeData, root, defaultNamespace); break;
  170. case SchemaTypes.Enum: map = ImportEnumMapping (typeData, root, defaultNamespace); break;
  171. case SchemaTypes.XmlSerializable: map = ImportXmlSerializableMapping (typeData, root, defaultNamespace); break;
  172. default: throw new NotSupportedException ("Type " + typeData.Type.FullName + " not supported for XML stialization");
  173. }
  174. map.RelatedMaps = relatedMaps;
  175. map.Format = SerializationFormat.Literal;
  176. Type[] extraTypes = includedTypes != null ? (Type[]) includedTypes.ToArray (typeof (Type)) : null;
  177. map.Source = new XmlTypeSerializationSource (typeData.Type, root, attributeOverrides, defaultNamespace, extraTypes);
  178. if (allowPrivateTypes) map.Source.CanBeGenerated = false;
  179. return map;
  180. } catch (InvalidOperationException ex) {
  181. throw new InvalidOperationException (string.Format (CultureInfo.InvariantCulture,
  182. "There was an error reflecting type '{0}'.", typeData.Type.FullName), ex);
  183. }
  184. }
  185. XmlTypeMapping CreateTypeMapping (TypeData typeData, XmlRootAttribute root, string defaultXmlType, string defaultNamespace)
  186. {
  187. string rootNamespace = defaultNamespace;
  188. string typeNamespace = null;
  189. string elementName;
  190. bool includeInSchema = true;
  191. XmlAttributes atts = null;
  192. bool nullable = true;
  193. if (defaultXmlType == null) defaultXmlType = typeData.XmlType;
  194. if (!typeData.IsListType)
  195. {
  196. if (attributeOverrides != null)
  197. atts = attributeOverrides[typeData.Type];
  198. if (atts != null && typeData.SchemaType == SchemaTypes.Primitive)
  199. throw new InvalidOperationException ("XmlRoot and XmlType attributes may not be specified for the type " + typeData.FullTypeName);
  200. }
  201. if (atts == null)
  202. atts = new XmlAttributes (typeData.Type);
  203. if (atts.XmlRoot != null && root == null)
  204. root = atts.XmlRoot;
  205. if (atts.XmlType != null)
  206. {
  207. if (atts.XmlType.Namespace != null && typeData.SchemaType != SchemaTypes.Enum)
  208. typeNamespace = atts.XmlType.Namespace;
  209. if (atts.XmlType.TypeName != null && atts.XmlType.TypeName != string.Empty)
  210. defaultXmlType = XmlConvert.EncodeLocalName (atts.XmlType.TypeName);
  211. includeInSchema = atts.XmlType.IncludeInSchema;
  212. }
  213. elementName = defaultXmlType;
  214. if (root != null)
  215. {
  216. if (root.ElementName.Length != 0)
  217. elementName = XmlConvert.EncodeLocalName(root.ElementName);
  218. if (root.Namespace != null)
  219. rootNamespace = root.Namespace;
  220. nullable = root.IsNullable;
  221. }
  222. if (rootNamespace == null) rootNamespace = "";
  223. if (typeNamespace == null) typeNamespace = rootNamespace;
  224. XmlTypeMapping map;
  225. switch (typeData.SchemaType) {
  226. case SchemaTypes.XmlSerializable:
  227. map = new XmlSerializableMapping (elementName, rootNamespace, typeData, defaultXmlType, typeNamespace);
  228. break;
  229. case SchemaTypes.Primitive:
  230. if (!typeData.IsXsdType)
  231. map = new XmlTypeMapping (elementName, rootNamespace,
  232. typeData, defaultXmlType, XmlSerializer.WsdlTypesNamespace);
  233. else
  234. map = new XmlTypeMapping (elementName, rootNamespace,
  235. typeData, defaultXmlType, typeNamespace);
  236. break;
  237. default:
  238. map = new XmlTypeMapping (elementName, rootNamespace, typeData, defaultXmlType, typeNamespace);
  239. break;
  240. }
  241. map.IncludeInSchema = includeInSchema;
  242. map.IsNullable = nullable;
  243. relatedMaps.Add (map);
  244. return map;
  245. }
  246. XmlTypeMapping ImportClassMapping (Type type, XmlRootAttribute root, string defaultNamespace)
  247. {
  248. TypeData typeData = TypeTranslator.GetTypeData (type);
  249. return ImportClassMapping (typeData, root, defaultNamespace);
  250. }
  251. XmlTypeMapping ImportClassMapping (TypeData typeData, XmlRootAttribute root, string defaultNamespace)
  252. {
  253. Type type = typeData.Type;
  254. XmlTypeMapping map = helper.GetRegisteredClrType (type, GetTypeNamespace (typeData, root, defaultNamespace));
  255. if (map != null) return map;
  256. if (!allowPrivateTypes)
  257. ReflectionHelper.CheckSerializableType (type, false);
  258. map = CreateTypeMapping (typeData, root, null, defaultNamespace);
  259. helper.RegisterClrType (map, type, map.XmlTypeNamespace);
  260. helper.RegisterSchemaType (map, map.XmlType, map.XmlTypeNamespace);
  261. // Import members
  262. ClassMap classMap = new ClassMap ();
  263. map.ObjectMap = classMap;
  264. ICollection members = GetReflectionMembers (type);
  265. foreach (XmlReflectionMember rmember in members)
  266. {
  267. string ns = map.XmlTypeNamespace;
  268. if (rmember.XmlAttributes.XmlIgnore) continue;
  269. if (rmember.DeclaringType != null && rmember.DeclaringType != type) {
  270. XmlTypeMapping bmap = ImportClassMapping (rmember.DeclaringType, root, defaultNamespace);
  271. ns = bmap.XmlTypeNamespace;
  272. }
  273. try {
  274. XmlTypeMapMember mem = CreateMapMember (type, rmember, ns);
  275. mem.CheckOptionalValueType (type);
  276. classMap.AddMember (mem);
  277. } catch (InvalidOperationException ex) {
  278. throw new InvalidOperationException (string.Format (
  279. CultureInfo.InvariantCulture, "There was an error" +
  280. " reflecting field '{0}'.", rmember.MemberName), ex);
  281. }
  282. }
  283. // Import extra classes
  284. if (type == typeof (object) && includedTypes != null)
  285. {
  286. foreach (Type intype in includedTypes)
  287. map.DerivedTypes.Add (ImportTypeMapping (intype, defaultNamespace));
  288. }
  289. // Register inheritance relations
  290. if (type.BaseType != null)
  291. {
  292. XmlTypeMapping bmap = ImportClassMapping (type.BaseType, root, defaultNamespace);
  293. ClassMap cbmap = bmap.ObjectMap as ClassMap;
  294. if (type.BaseType != typeof (object)) {
  295. map.BaseMap = bmap;
  296. if (!cbmap.HasSimpleContent)
  297. classMap.SetCanBeSimpleType (false);
  298. }
  299. // At this point, derived classes of this map must be already registered
  300. RegisterDerivedMap (bmap, map);
  301. if (cbmap.HasSimpleContent && classMap.ElementMembers != null && classMap.ElementMembers.Count != 1)
  302. throw new InvalidOperationException (String.Format (errSimple, map.TypeData.TypeName, map.BaseMap.TypeData.TypeName));
  303. }
  304. ImportIncludedTypes (type, defaultNamespace);
  305. if (classMap.XmlTextCollector != null && !classMap.HasSimpleContent)
  306. {
  307. XmlTypeMapMember mem = classMap.XmlTextCollector;
  308. if (mem.TypeData.Type != typeof(string) &&
  309. mem.TypeData.Type != typeof(string[]) &&
  310. mem.TypeData.Type != typeof(object[]) &&
  311. mem.TypeData.Type != typeof(XmlNode[]))
  312. throw new InvalidOperationException (String.Format (errSimple2, map.TypeData.TypeName, mem.Name, mem.TypeData.TypeName));
  313. }
  314. return map;
  315. }
  316. void RegisterDerivedMap (XmlTypeMapping map, XmlTypeMapping derivedMap)
  317. {
  318. map.DerivedTypes.Add (derivedMap);
  319. map.DerivedTypes.AddRange (derivedMap.DerivedTypes);
  320. if (map.BaseMap != null)
  321. RegisterDerivedMap (map.BaseMap, derivedMap);
  322. else {
  323. XmlTypeMapping obmap = ImportTypeMapping (typeof(object));
  324. if (obmap != map)
  325. obmap.DerivedTypes.Add (derivedMap);
  326. }
  327. }
  328. string GetTypeNamespace (TypeData typeData, XmlRootAttribute root, string defaultNamespace)
  329. {
  330. string typeNamespace = null;
  331. XmlAttributes atts = null;
  332. if (!typeData.IsListType)
  333. {
  334. if (attributeOverrides != null)
  335. atts = attributeOverrides[typeData.Type];
  336. }
  337. if (atts == null)
  338. atts = new XmlAttributes (typeData.Type);
  339. if (atts.XmlType != null)
  340. {
  341. if (atts.XmlType.Namespace != null && atts.XmlType.Namespace.Length != 0 && typeData.SchemaType != SchemaTypes.Enum)
  342. typeNamespace = atts.XmlType.Namespace;
  343. }
  344. if (typeNamespace != null && typeNamespace.Length != 0) return typeNamespace;
  345. if (atts.XmlRoot != null && root == null)
  346. root = atts.XmlRoot;
  347. if (root != null)
  348. {
  349. if (root.Namespace != null && root.Namespace.Length != 0)
  350. return root.Namespace;
  351. }
  352. if (defaultNamespace == null) return "";
  353. else return defaultNamespace;
  354. }
  355. XmlTypeMapping ImportListMapping (Type type, XmlRootAttribute root, string defaultNamespace, XmlAttributes atts, int nestingLevel)
  356. {
  357. TypeData typeData = TypeTranslator.GetTypeData (type);
  358. return ImportListMapping (typeData, root, defaultNamespace, atts, nestingLevel);
  359. }
  360. XmlTypeMapping ImportListMapping (TypeData typeData, XmlRootAttribute root, string defaultNamespace, XmlAttributes atts, int nestingLevel)
  361. {
  362. Type type = typeData.Type;
  363. ListMap obmap = new ListMap ();
  364. if (!allowPrivateTypes)
  365. ReflectionHelper.CheckSerializableType (type, true);
  366. if (atts == null) atts = new XmlAttributes();
  367. Type itemType = typeData.ListItemType;
  368. // warning: byte[][] should not be considered multiarray
  369. bool isMultiArray = (type.IsArray && (TypeTranslator.GetTypeData(itemType).SchemaType == SchemaTypes.Array) && itemType.IsArray);
  370. XmlTypeMapElementInfoList list = new XmlTypeMapElementInfoList();
  371. foreach (XmlArrayItemAttribute att in atts.XmlArrayItems)
  372. {
  373. if (att.NestingLevel != nestingLevel) continue;
  374. Type elemType = (att.Type != null) ? att.Type : itemType;
  375. XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (null, TypeTranslator.GetTypeData(elemType, att.DataType));
  376. elem.Namespace = att.Namespace != null ? att.Namespace : defaultNamespace;
  377. if (elem.Namespace == null) elem.Namespace = "";
  378. elem.Form = att.Form;
  379. elem.IsNullable = att.IsNullable && CanBeNull (elem.TypeData);
  380. elem.NestingLevel = att.NestingLevel;
  381. if (isMultiArray) {
  382. elem.MappedType = ImportListMapping (elemType, null, elem.Namespace, atts, nestingLevel + 1);
  383. } else if (elem.TypeData.IsComplexType) {
  384. elem.MappedType = ImportTypeMapping (elemType, null, elem.Namespace);
  385. }
  386. if (att.ElementName.Length != 0) {
  387. elem.ElementName = XmlConvert.EncodeLocalName (att.ElementName);
  388. } else if (elem.MappedType != null) {
  389. elem.ElementName = elem.MappedType.ElementName;
  390. } else {
  391. elem.ElementName = TypeTranslator.GetTypeData (elemType).XmlType;
  392. }
  393. list.Add (elem);
  394. }
  395. if (list.Count == 0)
  396. {
  397. XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (null, TypeTranslator.GetTypeData (itemType));
  398. if (isMultiArray)
  399. elem.MappedType = ImportListMapping (itemType, null, defaultNamespace, atts, nestingLevel + 1);
  400. else if (elem.TypeData.IsComplexType)
  401. elem.MappedType = ImportTypeMapping (itemType, null, defaultNamespace);
  402. if (elem.MappedType != null) {
  403. elem.ElementName = elem.MappedType.XmlType;
  404. } else {
  405. elem.ElementName = TypeTranslator.GetTypeData (itemType).XmlType;
  406. }
  407. elem.Namespace = (defaultNamespace != null) ? defaultNamespace : "";
  408. elem.IsNullable = CanBeNull (elem.TypeData);
  409. list.Add (elem);
  410. }
  411. obmap.ItemInfo = list;
  412. // If there can be different element names (types) in the array, then its name cannot
  413. // be "ArrayOfXXX" it must be something like ArrayOfChoiceNNN
  414. string baseName;
  415. if (list.Count > 1) {
  416. baseName = "ArrayOfChoice" + (arrayChoiceCount++);
  417. } else {
  418. XmlTypeMapElementInfo elem = ((XmlTypeMapElementInfo) list[0]);
  419. if (elem.MappedType != null) {
  420. baseName = TypeTranslator.GetArrayName (elem.MappedType.XmlType);
  421. } else {
  422. baseName = TypeTranslator.GetArrayName (elem.ElementName);
  423. }
  424. }
  425. // Avoid name colisions
  426. int nameCount = 1;
  427. string name = baseName;
  428. do {
  429. XmlTypeMapping foundMap = helper.GetRegisteredSchemaType (name, defaultNamespace);
  430. if (foundMap == null) nameCount = -1;
  431. else if (obmap.Equals (foundMap.ObjectMap) && typeData.Type == foundMap.TypeData.Type) return foundMap;
  432. else name = baseName + (nameCount++);
  433. }
  434. while (nameCount != -1);
  435. XmlTypeMapping map = CreateTypeMapping (typeData, root, name, defaultNamespace);
  436. map.ObjectMap = obmap;
  437. // Register any of the including types as a derived class of object
  438. XmlIncludeAttribute[] includes = (XmlIncludeAttribute[])type.GetCustomAttributes (typeof (XmlIncludeAttribute), false);
  439. XmlTypeMapping objectMapping = ImportTypeMapping (typeof(object));
  440. for (int i = 0; i < includes.Length; i++)
  441. {
  442. Type includedType = includes[i].Type;
  443. objectMapping.DerivedTypes.Add(ImportTypeMapping (includedType, null, defaultNamespace));
  444. }
  445. // Register this map as a derived class of object
  446. helper.RegisterSchemaType (map, name, defaultNamespace);
  447. ImportTypeMapping (typeof(object)).DerivedTypes.Add (map);
  448. return map;
  449. }
  450. XmlTypeMapping ImportXmlNodeMapping (TypeData typeData, XmlRootAttribute root, string defaultNamespace)
  451. {
  452. Type type = typeData.Type;
  453. XmlTypeMapping map = helper.GetRegisteredClrType (type, GetTypeNamespace (typeData, root, defaultNamespace));
  454. if (map != null) return map;
  455. map = CreateTypeMapping (typeData, root, null, defaultNamespace);
  456. helper.RegisterClrType (map, type, map.XmlTypeNamespace);
  457. if (type.BaseType != null)
  458. {
  459. XmlTypeMapping bmap = ImportTypeMapping (type.BaseType, root, defaultNamespace);
  460. if (type.BaseType != typeof (object))
  461. map.BaseMap = bmap;
  462. RegisterDerivedMap (bmap, map);
  463. }
  464. return map;
  465. }
  466. XmlTypeMapping ImportPrimitiveMapping (TypeData typeData, XmlRootAttribute root, string defaultNamespace)
  467. {
  468. Type type = typeData.Type;
  469. XmlTypeMapping map = helper.GetRegisteredClrType (type, GetTypeNamespace (typeData, root, defaultNamespace));
  470. if (map != null) return map;
  471. map = CreateTypeMapping (typeData, root, null, defaultNamespace);
  472. helper.RegisterClrType (map, type, map.XmlTypeNamespace);
  473. return map;
  474. }
  475. XmlTypeMapping ImportEnumMapping (TypeData typeData, XmlRootAttribute root, string defaultNamespace)
  476. {
  477. Type type = typeData.Type;
  478. XmlTypeMapping map = helper.GetRegisteredClrType (type, GetTypeNamespace (typeData, root, defaultNamespace));
  479. if (map != null) return map;
  480. if (!allowPrivateTypes)
  481. ReflectionHelper.CheckSerializableType (type, false);
  482. map = CreateTypeMapping (typeData, root, null, defaultNamespace);
  483. map.IsNullable = false;
  484. helper.RegisterClrType (map, type, map.XmlTypeNamespace);
  485. string [] names = Enum.GetNames (type);
  486. ArrayList members = new ArrayList();
  487. foreach (string name in names)
  488. {
  489. FieldInfo field = type.GetField (name);
  490. string xmlName = null;
  491. if (field.IsDefined(typeof(XmlIgnoreAttribute), false))
  492. continue;
  493. object[] atts = field.GetCustomAttributes (typeof(XmlEnumAttribute), false);
  494. if (atts.Length > 0) xmlName = ((XmlEnumAttribute)atts[0]).Name;
  495. if (xmlName == null) xmlName = name;
  496. long value = ((IConvertible) field.GetValue (null)).ToInt64 (CultureInfo.InvariantCulture);
  497. members.Add (new EnumMap.EnumMapMember (xmlName, name, value));
  498. }
  499. bool isFlags = type.IsDefined (typeof (FlagsAttribute), false);
  500. map.ObjectMap = new EnumMap ((EnumMap.EnumMapMember[])members.ToArray (typeof(EnumMap.EnumMapMember)), isFlags);
  501. ImportTypeMapping (typeof(object)).DerivedTypes.Add (map);
  502. return map;
  503. }
  504. XmlTypeMapping ImportXmlSerializableMapping (TypeData typeData, XmlRootAttribute root, string defaultNamespace)
  505. {
  506. Type type = typeData.Type;
  507. XmlTypeMapping map = helper.GetRegisteredClrType (type, GetTypeNamespace (typeData, root, defaultNamespace));
  508. if (map != null) return map;
  509. if (!allowPrivateTypes)
  510. ReflectionHelper.CheckSerializableType (type, false);
  511. map = CreateTypeMapping (typeData, root, null, defaultNamespace);
  512. helper.RegisterClrType (map, type, map.XmlTypeNamespace);
  513. return map;
  514. }
  515. void ImportIncludedTypes (Type type, string defaultNamespace)
  516. {
  517. XmlIncludeAttribute[] includes = (XmlIncludeAttribute[])type.GetCustomAttributes (typeof (XmlIncludeAttribute), false);
  518. for (int n=0; n<includes.Length; n++)
  519. {
  520. Type includedType = includes[n].Type;
  521. ImportTypeMapping (includedType, null, defaultNamespace);
  522. }
  523. }
  524. ICollection GetReflectionMembers (Type type)
  525. {
  526. // First we want to find the inheritance hierarchy in reverse order.
  527. Type currentType = type;
  528. ArrayList typeList = new ArrayList();
  529. typeList.Add(currentType);
  530. while (currentType != typeof(object))
  531. {
  532. currentType = currentType.BaseType; // Read the base type.
  533. typeList.Insert(0, currentType); // Insert at 0 to reverse the order.
  534. }
  535. // Read all Fields via reflection.
  536. ArrayList fieldList = new ArrayList();
  537. FieldInfo[] tfields = type.GetFields (BindingFlags.Instance | BindingFlags.Public);
  538. #if TARGET_JVM
  539. // This statement ensures fields are ordered starting from the base type.
  540. for (int ti=0; ti<typeList.Count; ti++) {
  541. for (int i=0; i<tfields.Length; i++) {
  542. FieldInfo field = tfields[i];
  543. if (field.DeclaringType == typeList[ti])
  544. fieldList.Add (field);
  545. }
  546. }
  547. #else
  548. currentType = null;
  549. int currentIndex = 0;
  550. foreach (FieldInfo field in tfields)
  551. {
  552. // This statement ensures fields are ordered starting from the base type.
  553. if (currentType != field.DeclaringType)
  554. {
  555. currentType = field.DeclaringType;
  556. currentIndex=0;
  557. }
  558. fieldList.Insert(currentIndex++, field);
  559. }
  560. #endif
  561. // Read all Properties via reflection.
  562. ArrayList propList = new ArrayList();
  563. PropertyInfo[] tprops = type.GetProperties (BindingFlags.Instance | BindingFlags.Public);
  564. #if TARGET_JVM
  565. // This statement ensures properties are ordered starting from the base type.
  566. for (int ti=0; ti<typeList.Count; ti++) {
  567. for (int i=0; i<tprops.Length; i++) {
  568. PropertyInfo prop = tprops[i];
  569. if (!prop.CanRead) continue;
  570. if (prop.GetIndexParameters().Length > 0) continue;
  571. if (prop.DeclaringType == typeList[ti])
  572. propList.Add (prop);
  573. }
  574. }
  575. #else
  576. currentType = null;
  577. currentIndex = 0;
  578. foreach (PropertyInfo prop in tprops)
  579. {
  580. // This statement ensures properties are ordered starting from the base type.
  581. if (currentType != prop.DeclaringType)
  582. {
  583. currentType = prop.DeclaringType;
  584. currentIndex = 0;
  585. }
  586. if (!prop.CanRead) continue;
  587. if (prop.GetIndexParameters().Length > 0) continue;
  588. propList.Insert(currentIndex++, prop);
  589. }
  590. #endif
  591. ArrayList members = new ArrayList();
  592. int fieldIndex=0;
  593. int propIndex=0;
  594. // We now step through the type hierarchy from the base (object) through
  595. // to the supplied class, as each step outputting all Fields, and then
  596. // all Properties. This is the exact same ordering as .NET 1.0/1.1.
  597. foreach (Type t in typeList)
  598. {
  599. // Add any fields matching the current DeclaringType.
  600. while (fieldIndex < fieldList.Count)
  601. {
  602. FieldInfo field = (FieldInfo)fieldList[fieldIndex];
  603. if (field.DeclaringType==t)
  604. {
  605. fieldIndex++;
  606. XmlAttributes atts = attributeOverrides[type, field.Name];
  607. if (atts == null) atts = new XmlAttributes (field);
  608. if (atts.XmlIgnore) continue;
  609. XmlReflectionMember member = new XmlReflectionMember(field.Name, field.FieldType, atts);
  610. member.DeclaringType = field.DeclaringType;
  611. members.Add(member);
  612. }
  613. else break;
  614. }
  615. // Add any properties matching the current DeclaringType.
  616. while (propIndex < propList.Count)
  617. {
  618. PropertyInfo prop = (PropertyInfo)propList[propIndex];
  619. if (prop.DeclaringType==t)
  620. {
  621. propIndex++;
  622. XmlAttributes atts = attributeOverrides[type, prop.Name];
  623. if (atts == null) atts = new XmlAttributes (prop);
  624. if (atts.XmlIgnore) continue;
  625. if (!prop.CanWrite && (TypeTranslator.GetTypeData (prop.PropertyType).SchemaType != SchemaTypes.Array || prop.PropertyType.IsArray)) continue;
  626. XmlReflectionMember member = new XmlReflectionMember(prop.Name, prop.PropertyType, atts);
  627. member.DeclaringType = prop.DeclaringType;
  628. members.Add(member);
  629. }
  630. else break;
  631. }
  632. }
  633. return members;
  634. }
  635. private XmlTypeMapMember CreateMapMember (Type declaringType, XmlReflectionMember rmember, string defaultNamespace)
  636. {
  637. XmlTypeMapMember mapMember;
  638. XmlAttributes atts = rmember.XmlAttributes;
  639. TypeData typeData = TypeTranslator.GetTypeData (rmember.MemberType);
  640. if (atts.XmlAnyAttribute != null)
  641. {
  642. if ( (rmember.MemberType.FullName == "System.Xml.XmlAttribute[]") ||
  643. (rmember.MemberType.FullName == "System.Xml.XmlNode[]") )
  644. {
  645. mapMember = new XmlTypeMapMemberAnyAttribute();
  646. }
  647. else
  648. throw new InvalidOperationException ("XmlAnyAttributeAttribute can only be applied to members of type XmlAttribute[] or XmlNode[]");
  649. }
  650. else if (atts.XmlAnyElements != null && atts.XmlAnyElements.Count > 0)
  651. {
  652. if ( (rmember.MemberType.FullName == "System.Xml.XmlElement[]") ||
  653. (rmember.MemberType.FullName == "System.Xml.XmlNode[]") ||
  654. (rmember.MemberType.FullName == "System.Xml.XmlElement"))
  655. {
  656. XmlTypeMapMemberAnyElement member = new XmlTypeMapMemberAnyElement();
  657. member.ElementInfo = ImportAnyElementInfo (defaultNamespace, rmember, member, atts);
  658. mapMember = member;
  659. }
  660. else
  661. throw new InvalidOperationException ("XmlAnyElementAttribute can only be applied to members of type XmlElement, XmlElement[] or XmlNode[]");
  662. }
  663. else if (atts.Xmlns)
  664. {
  665. XmlTypeMapMemberNamespaces mapNamespaces = new XmlTypeMapMemberNamespaces ();
  666. mapMember = mapNamespaces;
  667. }
  668. else if (atts.XmlAttribute != null)
  669. {
  670. // An attribute
  671. if (atts.XmlElements != null && atts.XmlElements.Count > 0)
  672. throw new Exception ("XmlAttributeAttribute and XmlElementAttribute cannot be applied to the same member");
  673. XmlTypeMapMemberAttribute mapAttribute = new XmlTypeMapMemberAttribute ();
  674. if (atts.XmlAttribute.AttributeName.Length == 0)
  675. mapAttribute.AttributeName = rmember.MemberName;
  676. else
  677. mapAttribute.AttributeName = atts.XmlAttribute.AttributeName;
  678. mapAttribute.AttributeName = XmlConvert.EncodeLocalName (mapAttribute.AttributeName);
  679. if (typeData.IsComplexType)
  680. mapAttribute.MappedType = ImportTypeMapping (typeData.Type, null, mapAttribute.Namespace);
  681. if (atts.XmlAttribute.Namespace != null && atts.XmlAttribute.Namespace != defaultNamespace)
  682. {
  683. if (atts.XmlAttribute.Form == XmlSchemaForm.Unqualified)
  684. throw new InvalidOperationException ("The Form property may not be 'Unqualified' when an explicit Namespace property is present");
  685. mapAttribute.Form = XmlSchemaForm.Qualified;
  686. mapAttribute.Namespace = atts.XmlAttribute.Namespace;
  687. }
  688. else
  689. {
  690. mapAttribute.Form = atts.XmlAttribute.Form;
  691. if (atts.XmlAttribute.Form == XmlSchemaForm.Qualified)
  692. mapAttribute.Namespace = defaultNamespace;
  693. else
  694. mapAttribute.Namespace = "";
  695. }
  696. typeData = TypeTranslator.GetTypeData(rmember.MemberType, atts.XmlAttribute.DataType);
  697. mapMember = mapAttribute;
  698. }
  699. else if (typeData.SchemaType == SchemaTypes.Array)
  700. {
  701. // If the member has a single XmlElementAttribute and the type is the type of the member,
  702. // then it is not a flat list
  703. if (atts.XmlElements.Count > 1 ||
  704. (atts.XmlElements.Count == 1 && atts.XmlElements[0].Type != typeData.Type) ||
  705. (atts.XmlText != null))
  706. {
  707. // A flat list
  708. // TODO: check that it does not have XmlArrayAttribute
  709. XmlTypeMapMemberFlatList member = new XmlTypeMapMemberFlatList ();
  710. member.ListMap = new ListMap ();
  711. member.ListMap.ItemInfo = ImportElementInfo (declaringType, XmlConvert.EncodeLocalName (rmember.MemberName), defaultNamespace, typeData.ListItemType, member, atts);
  712. member.ElementInfo = member.ListMap.ItemInfo;
  713. member.ListMap.ChoiceMember = member.ChoiceMember;
  714. mapMember = member;
  715. }
  716. else
  717. {
  718. // A list
  719. XmlTypeMapMemberList member = new XmlTypeMapMemberList ();
  720. // Creates an ElementInfo that identifies the array instance.
  721. member.ElementInfo = new XmlTypeMapElementInfoList();
  722. XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (member, typeData);
  723. elem.ElementName = XmlConvert.EncodeLocalName((atts.XmlArray != null && atts.XmlArray.ElementName.Length != 0) ? atts.XmlArray.ElementName : rmember.MemberName);
  724. elem.Namespace = (atts.XmlArray != null && atts.XmlArray.Namespace != null) ? atts.XmlArray.Namespace : defaultNamespace;
  725. elem.MappedType = ImportListMapping (rmember.MemberType, null, elem.Namespace, atts, 0);
  726. elem.IsNullable = (atts.XmlArray != null) ? atts.XmlArray.IsNullable : false;
  727. elem.Form = (atts.XmlArray != null) ? atts.XmlArray.Form : XmlSchemaForm.Qualified;
  728. member.ElementInfo.Add (elem);
  729. mapMember = member;
  730. }
  731. }
  732. else
  733. {
  734. // An element
  735. XmlTypeMapMemberElement member = new XmlTypeMapMemberElement ();
  736. member.ElementInfo = ImportElementInfo (declaringType, XmlConvert.EncodeLocalName(rmember.MemberName), defaultNamespace, rmember.MemberType, member, atts);
  737. mapMember = member;
  738. }
  739. mapMember.DefaultValue = atts.XmlDefaultValue;
  740. mapMember.TypeData = typeData;
  741. mapMember.Name = rmember.MemberName;
  742. mapMember.IsReturnValue = rmember.IsReturnValue;
  743. return mapMember;
  744. }
  745. XmlTypeMapElementInfoList ImportElementInfo (Type cls, string defaultName, string defaultNamespace, Type defaultType, XmlTypeMapMemberElement member, XmlAttributes atts)
  746. {
  747. EnumMap choiceEnumMap = null;
  748. Type choiceEnumType = null;
  749. XmlTypeMapElementInfoList list = new XmlTypeMapElementInfoList();
  750. ImportTextElementInfo (list, defaultType, member, atts);
  751. if (atts.XmlChoiceIdentifier != null) {
  752. if (cls == null)
  753. throw new InvalidOperationException ("XmlChoiceIdentifierAttribute not supported in this context.");
  754. member.ChoiceMember = atts.XmlChoiceIdentifier.MemberName;
  755. MemberInfo[] mems = cls.GetMember (member.ChoiceMember, BindingFlags.Instance|BindingFlags.Public);
  756. if (mems.Length == 0)
  757. throw new InvalidOperationException ("Choice member '" + member.ChoiceMember + "' not found in class '" + cls);
  758. if (mems[0] is PropertyInfo) {
  759. PropertyInfo pi = (PropertyInfo)mems[0];
  760. if (!pi.CanWrite || !pi.CanRead)
  761. throw new InvalidOperationException ("Choice property '" + member.ChoiceMember + "' must be read/write.");
  762. choiceEnumType = pi.PropertyType;
  763. }
  764. else choiceEnumType = ((FieldInfo)mems[0]).FieldType;
  765. member.ChoiceTypeData = TypeTranslator.GetTypeData (choiceEnumType);
  766. if (choiceEnumType.IsArray)
  767. choiceEnumType = choiceEnumType.GetElementType ();
  768. choiceEnumMap = ImportTypeMapping (choiceEnumType).ObjectMap as EnumMap;
  769. if (choiceEnumMap == null)
  770. throw new InvalidOperationException ("The member '" + mems[0].Name + "' is not a valid target for XmlChoiceIdentifierAttribute.");
  771. }
  772. if (atts.XmlElements.Count == 0 && list.Count == 0)
  773. {
  774. XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (member, TypeTranslator.GetTypeData(defaultType));
  775. elem.ElementName = defaultName;
  776. elem.Namespace = defaultNamespace;
  777. if (elem.TypeData.IsComplexType)
  778. elem.MappedType = ImportTypeMapping (defaultType, null, defaultNamespace);
  779. list.Add (elem);
  780. }
  781. bool multiType = (atts.XmlElements.Count > 1);
  782. foreach (XmlElementAttribute att in atts.XmlElements)
  783. {
  784. Type elemType = (att.Type != null) ? att.Type : defaultType;
  785. XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (member, TypeTranslator.GetTypeData(elemType, att.DataType));
  786. elem.Form = att.Form;
  787. if (elem.Form != XmlSchemaForm.Unqualified)
  788. elem.Namespace = (att.Namespace != null) ? att.Namespace : defaultNamespace;
  789. elem.IsNullable = att.IsNullable;
  790. if (elem.IsNullable && elem.TypeData.IsValueType)
  791. throw new InvalidOperationException ("IsNullable may not be 'true' for value type " + elem.TypeData.FullTypeName + " in member '" + defaultName + "'");
  792. if (elem.TypeData.IsComplexType)
  793. {
  794. if (att.DataType.Length != 0) throw new InvalidOperationException (
  795. string.Format(CultureInfo.InvariantCulture, "'{0}' is "
  796. + "an invalid value for '{1}.{2}' of type '{3}'. "
  797. + "The property may only be specified for primitive types.",
  798. att.DataType, cls.FullName, defaultName,
  799. elem.TypeData.FullTypeName));
  800. elem.MappedType = ImportTypeMapping (elemType, null, elem.Namespace);
  801. }
  802. if (att.ElementName.Length != 0) {
  803. elem.ElementName = XmlConvert.EncodeLocalName(att.ElementName);
  804. } else if (multiType) {
  805. if (elem.MappedType != null) {
  806. elem.ElementName = elem.MappedType.ElementName;
  807. } else {
  808. elem.ElementName = TypeTranslator.GetTypeData (elemType).XmlType;
  809. }
  810. } else {
  811. elem.ElementName = defaultName;
  812. }
  813. if (choiceEnumMap != null) {
  814. string cname = choiceEnumMap.GetEnumName (choiceEnumType.FullName, elem.ElementName);
  815. if (cname == null)
  816. throw new InvalidOperationException (string.Format (
  817. CultureInfo.InvariantCulture, "Type {0} is missing"
  818. + " enumeration value '{1}' for element '{1} from"
  819. + " namespace '{2}'.", choiceEnumType, elem.ElementName,
  820. elem.Namespace));
  821. elem.ChoiceValue = Enum.Parse (choiceEnumType, cname);
  822. }
  823. list.Add (elem);
  824. }
  825. return list;
  826. }
  827. XmlTypeMapElementInfoList ImportAnyElementInfo (string defaultNamespace, XmlReflectionMember rmember, XmlTypeMapMemberElement member, XmlAttributes atts)
  828. {
  829. XmlTypeMapElementInfoList list = new XmlTypeMapElementInfoList();
  830. ImportTextElementInfo (list, rmember.MemberType, member, atts);
  831. foreach (XmlAnyElementAttribute att in atts.XmlAnyElements)
  832. {
  833. XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (member, TypeTranslator.GetTypeData(typeof(XmlElement)));
  834. if (att.Name.Length != 0)
  835. {
  836. elem.ElementName = XmlConvert.EncodeLocalName(att.Name);
  837. elem.Namespace = (att.Namespace != null) ? att.Namespace : "";
  838. }
  839. else
  840. {
  841. elem.IsUnnamedAnyElement = true;
  842. elem.Namespace = defaultNamespace;
  843. if (att.Namespace != null)
  844. throw new InvalidOperationException ("The element " + rmember.MemberName + " has been attributed with an XmlAnyElementAttribute and a namespace '" + att.Namespace + "', but no name. When a namespace is supplied, a name is also required. Supply a name or remove the namespace.");
  845. }
  846. list.Add (elem);
  847. }
  848. return list;
  849. }
  850. void ImportTextElementInfo (XmlTypeMapElementInfoList list, Type defaultType, XmlTypeMapMemberElement member, XmlAttributes atts)
  851. {
  852. if (atts.XmlText != null)
  853. {
  854. member.IsXmlTextCollector = true;
  855. if (atts.XmlText.Type != null) {
  856. TypeData td = TypeTranslator.GetTypeData (defaultType);
  857. if ((td.SchemaType == SchemaTypes.Primitive || td.SchemaType == SchemaTypes.Enum) && atts.XmlText.Type != defaultType) {
  858. throw new InvalidOperationException ("The type for XmlText may not be specified for primitive types.");
  859. }
  860. defaultType = atts.XmlText.Type;
  861. }
  862. if (defaultType == typeof(XmlNode)) defaultType = typeof(XmlText); // Nodes must be text nodes
  863. XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (member, TypeTranslator.GetTypeData(defaultType, atts.XmlText.DataType));
  864. if (elem.TypeData.SchemaType != SchemaTypes.Primitive &&
  865. elem.TypeData.SchemaType != SchemaTypes.Enum &&
  866. elem.TypeData.SchemaType != SchemaTypes.XmlNode &&
  867. !(elem.TypeData.SchemaType == SchemaTypes.Array && elem.TypeData.ListItemTypeData.SchemaType == SchemaTypes.XmlNode)
  868. )
  869. throw new InvalidOperationException ("XmlText cannot be used to encode complex types");
  870. elem.IsTextElement = true;
  871. elem.WrappedElement = false;
  872. list.Add (elem);
  873. }
  874. }
  875. bool CanBeNull (TypeData type)
  876. {
  877. return (type.SchemaType != SchemaTypes.Primitive || type.Type == typeof (string));
  878. }
  879. public void IncludeType (Type type)
  880. {
  881. if (type == null)
  882. throw new ArgumentNullException ("type");
  883. if (includedTypes == null) includedTypes = new ArrayList ();
  884. if (!includedTypes.Contains (type))
  885. includedTypes.Add (type);
  886. if (relatedMaps.Count > 0) {
  887. foreach (XmlTypeMapping map in (ArrayList) relatedMaps.Clone ()) {
  888. if (map.TypeData.Type == typeof(object))
  889. map.DerivedTypes.Add (ImportTypeMapping (type));
  890. }
  891. }
  892. }
  893. public void IncludeTypes (ICustomAttributeProvider provider)
  894. {
  895. object[] ats = provider.GetCustomAttributes (typeof(XmlIncludeAttribute), true);
  896. foreach (XmlIncludeAttribute at in ats)
  897. IncludeType (at.Type);
  898. }
  899. #endregion // Methods
  900. }
  901. }