(DISTFILES): Comment out a few missing files.
[mono-project.git] / mcs / class / System.XML / System.Xml.Serialization / SoapReflectionImporter.cs
blobafc83a8ae13b2231b8d1f1bffa0011ac8e64e2a9
1 //
2 // System.Xml.Serialization.SoapReflectionImporter
3 //
4 // Author:
5 // Tim Coleman (tim@timcoleman.com)
6 //
7 // Copyright (C) Tim Coleman, 2002
8 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 //
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 //
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.Reflection;
32 using System.Xml;
33 using System.Xml.Schema;
34 using System.Collections;
36 namespace System.Xml.Serialization {
37 public class SoapReflectionImporter {
39 SoapAttributeOverrides attributeOverrides;
40 string initialDefaultNamespace;
41 ArrayList includedTypes;
42 ArrayList relatedMaps = new ArrayList ();
43 ReflectionHelper helper = new ReflectionHelper();
45 #region Constructors
47 public SoapReflectionImporter (): this (null, null)
51 public SoapReflectionImporter (SoapAttributeOverrides attributeOverrides): this (attributeOverrides, null)
55 public SoapReflectionImporter (string defaultNamespace): this (null, defaultNamespace)
59 public SoapReflectionImporter (SoapAttributeOverrides attributeOverrides, string defaultNamespace)
61 if (defaultNamespace == null) initialDefaultNamespace = String.Empty;
62 else initialDefaultNamespace = defaultNamespace;
64 if (attributeOverrides == null) this.attributeOverrides = new SoapAttributeOverrides();
65 else this.attributeOverrides = attributeOverrides;
68 #endregion // Constructors
70 #region Methods
72 public XmlMembersMapping ImportMembersMapping (string elementName, string ns, XmlReflectionMember[] members)
74 return ImportMembersMapping (elementName, ns, members, true, true, false);
77 public XmlMembersMapping ImportMembersMapping (string elementName, string ns, XmlReflectionMember[] members, bool hasWrapperElement, bool writeAccessors)
79 return ImportMembersMapping (elementName, ns, members, hasWrapperElement, writeAccessors, false);
82 public XmlMembersMapping ImportMembersMapping (string elementName, string ns, XmlReflectionMember[] members, bool hasWrapperElement, bool writeAccessors, bool validate)
84 XmlMemberMapping[] mapping = new XmlMemberMapping[members.Length];
85 for (int n=0; n<members.Length; n++)
87 XmlTypeMapMember mapMem = CreateMapMember (members[n], ns);
88 mapping[n] = new XmlMemberMapping (members[n].MemberName, ns, mapMem, true);
90 XmlMembersMapping mps = new XmlMembersMapping (elementName, ns, hasWrapperElement, writeAccessors, mapping);
91 mps.RelatedMaps = relatedMaps;
92 mps.Format = SerializationFormat.Encoded;
93 Type[] extraTypes = includedTypes != null ? (Type[])includedTypes.ToArray(typeof(Type)) : null;
94 mps.Source = new MembersSerializationSource (elementName, hasWrapperElement, members, writeAccessors, false, null, extraTypes);
95 return mps;
98 public XmlTypeMapping ImportTypeMapping (Type type)
100 return ImportTypeMapping (type, null);
103 public XmlTypeMapping ImportTypeMapping (Type type, string defaultNamespace)
105 if (type == null)
106 throw new ArgumentNullException ("type");
108 if (type == typeof (void))
109 throw new InvalidOperationException ("Type " + type.Name + " may not be serialized.");
111 if (defaultNamespace == null) defaultNamespace = initialDefaultNamespace;
112 if (defaultNamespace == null) defaultNamespace = string.Empty;
114 XmlTypeMapping map;
115 switch (TypeTranslator.GetTypeData(type).SchemaType)
117 case SchemaTypes.Class: map = ImportClassMapping (type, defaultNamespace); break;
118 case SchemaTypes.Array: map = ImportListMapping (type, defaultNamespace); break;
119 case SchemaTypes.XmlNode: throw CreateTypeException (type);
120 case SchemaTypes.Primitive: map = ImportPrimitiveMapping (type, defaultNamespace); break;
121 case SchemaTypes.Enum: map = ImportEnumMapping (type, defaultNamespace); break;
122 case SchemaTypes.XmlSerializable:
123 default: throw new NotSupportedException ("Type " + type.FullName + " not supported for XML serialization");
125 map.RelatedMaps = relatedMaps;
126 map.Format = SerializationFormat.Encoded;
127 Type[] extraTypes = includedTypes != null ? (Type[])includedTypes.ToArray(typeof(Type)) : null;
128 map.Source = new SoapTypeSerializationSource (type, attributeOverrides, defaultNamespace, extraTypes);
129 return map;
132 XmlTypeMapping CreateTypeMapping (TypeData typeData, string defaultXmlType, string defaultNamespace)
134 string membersNamespace = defaultNamespace;
135 bool includeInSchema = true;
137 SoapAttributes atts = null;
138 if (defaultXmlType == null) defaultXmlType = typeData.XmlType;
140 if (!typeData.IsListType)
142 if (attributeOverrides != null)
143 atts = attributeOverrides[typeData.Type];
145 if (atts != null && typeData.SchemaType == SchemaTypes.Primitive)
146 throw new InvalidOperationException ("SoapType attribute may not be specified for the type " + typeData.FullTypeName);
149 if (atts == null)
150 atts = new SoapAttributes (typeData.Type);
152 if (atts.SoapType != null)
154 if (atts.SoapType.Namespace != null && atts.SoapType.Namespace != string.Empty)
155 membersNamespace = atts.SoapType.Namespace;
157 if (atts.SoapType.TypeName != null && atts.SoapType.TypeName != string.Empty)
158 defaultXmlType = atts.SoapType.TypeName;
160 includeInSchema = atts.SoapType.IncludeInSchema;
163 if (membersNamespace == null) membersNamespace = "";
164 XmlTypeMapping map = new XmlTypeMapping (defaultXmlType, membersNamespace, typeData, defaultXmlType, membersNamespace);
165 map.IncludeInSchema = includeInSchema;
166 relatedMaps.Add (map);
168 return map;
171 XmlTypeMapping ImportClassMapping (Type type, string defaultNamespace)
173 if (type.IsValueType) throw CreateStructException (type);
174 if (type == typeof (object)) defaultNamespace = XmlSchema.Namespace;
176 ReflectionHelper.CheckSerializableType (type, false);
178 TypeData typeData = TypeTranslator.GetTypeData (type);
179 XmlTypeMapping map = helper.GetRegisteredClrType (type, GetTypeNamespace (typeData, defaultNamespace));
180 if (map != null) return map;
182 map = CreateTypeMapping (typeData, null, defaultNamespace);
183 helper.RegisterClrType (map, type, map.Namespace);
184 map.MultiReferenceType = true;
186 ClassMap classMap = new ClassMap ();
187 map.ObjectMap = classMap;
189 // Import members
193 ICollection members = GetReflectionMembers (type);
194 foreach (XmlReflectionMember rmember in members)
196 if (rmember.SoapAttributes.SoapIgnore) continue;
197 classMap.AddMember (CreateMapMember (rmember, map.Namespace));
200 catch (Exception ex)
202 throw helper.CreateError (map, ex.Message);
205 // Import included classes
207 SoapIncludeAttribute[] includes = (SoapIncludeAttribute[])type.GetCustomAttributes (typeof (SoapIncludeAttribute), false);
208 for (int n=0; n<includes.Length; n++)
210 Type includedType = includes[n].Type;
211 ImportTypeMapping (includedType);
214 if (type == typeof (object) && includedTypes != null)
216 foreach (Type intype in includedTypes)
217 map.DerivedTypes.Add (ImportTypeMapping (intype));
220 // Register inheritance relations
222 if (type.BaseType != null)
224 XmlTypeMapping bmap = ImportClassMapping (type.BaseType, defaultNamespace);
226 if (type.BaseType != typeof (object))
227 map.BaseMap = bmap;
229 // At this point, derived classes of this map must be already registered
231 RegisterDerivedMap (bmap, map);
234 return map;
237 void RegisterDerivedMap (XmlTypeMapping map, XmlTypeMapping derivedMap)
239 map.DerivedTypes.Add (derivedMap);
240 map.DerivedTypes.AddRange (derivedMap.DerivedTypes);
242 if (map.BaseMap != null)
243 RegisterDerivedMap (map.BaseMap, derivedMap);
244 else {
245 XmlTypeMapping obmap = ImportTypeMapping (typeof(object));
246 if (obmap != map)
247 obmap.DerivedTypes.Add (derivedMap);
251 string GetTypeNamespace (TypeData typeData, string defaultNamespace)
253 string membersNamespace = defaultNamespace;
255 SoapAttributes atts = null;
257 if (!typeData.IsListType)
259 if (attributeOverrides != null)
260 atts = attributeOverrides[typeData.Type];
263 if (atts == null)
264 atts = new SoapAttributes (typeData.Type);
266 if (atts.SoapType != null)
268 if (atts.SoapType.Namespace != null && atts.SoapType.Namespace != string.Empty)
269 membersNamespace = atts.SoapType.Namespace;
272 if (membersNamespace == null) return "";
273 else return membersNamespace;
276 XmlTypeMapping ImportListMapping (Type type, string defaultNamespace)
278 TypeData typeData = TypeTranslator.GetTypeData (type);
279 XmlTypeMapping map = helper.GetRegisteredClrType (type, XmlSerializer.EncodingNamespace);
280 if (map != null) return map;
282 ListMap obmap = new ListMap ();
283 TypeData itemTypeData = typeData.ListItemTypeData;
285 map = CreateTypeMapping (typeData, "Array", XmlSerializer.EncodingNamespace);
286 helper.RegisterClrType (map, type, XmlSerializer.EncodingNamespace);
287 map.MultiReferenceType = true;
288 map.ObjectMap = obmap;
290 XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (null, itemTypeData);
292 if (elem.TypeData.IsComplexType) {
293 elem.MappedType = ImportTypeMapping (typeData.ListItemType, defaultNamespace);
294 elem.TypeData = elem.MappedType.TypeData;
297 elem.ElementName = "Item";
298 elem.Namespace = string.Empty;
299 elem.IsNullable = true; // By default, items are nullable
301 XmlTypeMapElementInfoList list = new XmlTypeMapElementInfoList();
302 list.Add (elem);
304 obmap.ItemInfo = list;
305 XmlTypeMapping objMap = ImportTypeMapping (typeof(object), defaultNamespace);
306 objMap.DerivedTypes.Add (map);
308 // Register any of the including types as a derived class of object
309 SoapIncludeAttribute[] includes = (SoapIncludeAttribute[])type.GetCustomAttributes (typeof (SoapIncludeAttribute), false);
310 for (int i = 0; i < includes.Length; i++)
312 Type includedType = includes[i].Type;
313 objMap.DerivedTypes.Add(ImportTypeMapping (includedType, defaultNamespace));
316 return map;
319 XmlTypeMapping ImportPrimitiveMapping (Type type, string defaultNamespace)
321 TypeData typeData = TypeTranslator.GetTypeData (type);
322 XmlTypeMapping map = helper.GetRegisteredClrType (type, GetTypeNamespace (typeData, defaultNamespace));
323 if (map != null) return map;
324 map = CreateTypeMapping (typeData, null, defaultNamespace);
325 helper.RegisterClrType (map, type, map.Namespace);
326 return map;
330 XmlTypeMapping ImportEnumMapping (Type type, string defaultNamespace)
332 TypeData typeData = TypeTranslator.GetTypeData (type);
333 XmlTypeMapping map = helper.GetRegisteredClrType (type, GetTypeNamespace (typeData, defaultNamespace));
334 if (map != null) return map;
336 ReflectionHelper.CheckSerializableType (type, false);
338 map = CreateTypeMapping (typeData, null, defaultNamespace);
339 helper.RegisterClrType (map, type, map.Namespace);
341 map.MultiReferenceType = true;
343 string [] names = Enum.GetNames (type);
344 EnumMap.EnumMapMember[] members = new EnumMap.EnumMapMember[names.Length];
345 for (int n=0; n<names.Length; n++)
347 MemberInfo[] mem = type.GetMember (names[n]);
348 string xmlName = names[n];
349 object[] atts = mem[0].GetCustomAttributes (typeof(SoapEnumAttribute), false);
350 if (atts.Length > 0) xmlName = ((SoapEnumAttribute)atts[0]).Name;
351 members[n] = new EnumMap.EnumMapMember (xmlName, names[n]);
354 bool isFlags = type.GetCustomAttributes (typeof(FlagsAttribute),false).Length > 0;
355 map.ObjectMap = new EnumMap (members, isFlags);
356 ImportTypeMapping (typeof(object), defaultNamespace).DerivedTypes.Add (map);
357 return map;
360 ICollection GetReflectionMembers (Type type)
362 ArrayList members = new ArrayList();
363 PropertyInfo[] properties = type.GetProperties (BindingFlags.Instance | BindingFlags.Public);
364 foreach (PropertyInfo prop in properties)
366 if (!prop.CanRead) continue;
367 if (!prop.CanWrite && TypeTranslator.GetTypeData (prop.PropertyType).SchemaType != SchemaTypes.Array)
368 continue;
370 SoapAttributes atts = attributeOverrides[type, prop.Name];
371 if (atts == null) atts = new SoapAttributes (prop);
372 if (atts.SoapIgnore) continue;
373 XmlReflectionMember member = new XmlReflectionMember(prop.Name, prop.PropertyType, atts);
374 members.Add (member);
377 FieldInfo[] fields = type.GetFields (BindingFlags.Instance | BindingFlags.Public);
378 foreach (FieldInfo field in fields)
380 SoapAttributes atts = attributeOverrides[type, field.Name];
381 if (atts == null) atts = new SoapAttributes (field);
382 if (atts.SoapIgnore) continue;
383 XmlReflectionMember member = new XmlReflectionMember(field.Name, field.FieldType, atts);
384 members.Add (member);
386 return members;
389 private XmlTypeMapMember CreateMapMember (XmlReflectionMember rmember, string defaultNamespace)
391 XmlTypeMapMember mapMember;
392 SoapAttributes atts = rmember.SoapAttributes;
393 TypeData typeData = TypeTranslator.GetTypeData (rmember.MemberType);
395 if (atts.SoapAttribute != null)
397 // An attribute
399 if (atts.SoapElement != null)
400 throw new Exception ("SoapAttributeAttribute and SoapElementAttribute cannot be applied to the same member");
402 XmlTypeMapMemberAttribute mapAttribute = new XmlTypeMapMemberAttribute ();
403 if (atts.SoapAttribute.AttributeName == null)
404 mapAttribute.AttributeName = rmember.MemberName;
405 else
406 mapAttribute.AttributeName = atts.SoapAttribute.AttributeName;
408 mapAttribute.Namespace = (atts.SoapAttribute.Namespace != null) ? atts.SoapAttribute.Namespace : "";
409 if (typeData.IsComplexType)
410 mapAttribute.MappedType = ImportTypeMapping (typeData.Type, defaultNamespace);
412 typeData = TypeTranslator.GetTypeData (rmember.MemberType, atts.SoapAttribute.DataType);
413 mapMember = mapAttribute;
415 else
417 if (typeData.SchemaType == SchemaTypes.Array) mapMember = new XmlTypeMapMemberList ();
418 else mapMember = new XmlTypeMapMemberElement ();
420 if (atts.SoapElement != null && atts.SoapElement.DataType != null)
421 typeData = TypeTranslator.GetTypeData (rmember.MemberType, atts.SoapElement.DataType);
423 // Creates an ElementInfo that identifies the element
424 XmlTypeMapElementInfoList infoList = new XmlTypeMapElementInfoList();
425 XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (mapMember, typeData);
427 elem.ElementName = (atts.SoapElement != null && atts.SoapElement.ElementName != null) ? atts.SoapElement.ElementName : rmember.MemberName;
428 elem.Namespace = string.Empty;
429 elem.IsNullable = (atts.SoapElement != null) ? atts.SoapElement.IsNullable : false;
430 if (typeData.IsComplexType)
431 elem.MappedType = ImportTypeMapping (typeData.Type, defaultNamespace);
433 infoList.Add (elem);
434 ((XmlTypeMapMemberElement)mapMember).ElementInfo = infoList;
437 mapMember.TypeData = typeData;
438 mapMember.Name = rmember.MemberName;
439 mapMember.IsReturnValue = rmember.IsReturnValue;
440 return mapMember;
443 public void IncludeType (Type type)
445 if (type == null)
446 throw new ArgumentNullException ("type");
448 if (includedTypes == null) includedTypes = new ArrayList ();
449 if (!includedTypes.Contains (type))
450 includedTypes.Add (type);
453 public void IncludeTypes (ICustomAttributeProvider provider)
455 object[] ats = provider.GetCustomAttributes (typeof(SoapIncludeAttribute), true);
456 foreach (SoapIncludeAttribute at in ats)
457 IncludeType (at.Type);
460 Exception CreateTypeException (Type type)
462 return new NotSupportedException ("The type " + type.FullName + " may not be serialized with SOAP-encoded messages. Set the Use for your message to Literal");
465 Exception CreateStructException (Type type)
467 return new NotSupportedException ("Cannot serialize " + type.FullName + ". Nested structs are not supported with encoded SOAP");
473 #endregion // Methods