* SerializationCodeGenerator.cs: Several fixes: generate valid names for
[mono.git] / mcs / class / System.XML / System.Xml.Serialization / XmlReflectionImporter.cs
index c33c032c40fa0992f0cd7f40241a0c07ac148453..59a62f8c575d0439ec0c2a04a7c2c6464d0f0817 100644 (file)
@@ -12,6 +12,7 @@
 
 using System.Reflection;
 using System.Collections;
+using System.Xml.Schema;
 
 namespace System.Xml.Serialization {
        public class XmlReflectionImporter {
@@ -26,7 +27,10 @@ namespace System.Xml.Serialization {
 
                static readonly string errSimple = "Cannot serialize object of type '{0}'. Base " +
                        "type '{1}' has simpleContent and can be only extended by adding XmlAttribute " +
-                       "elements. Please consider changing XmlTextMember of the base class to string array";
+                       "elements. Please consider changing XmlText member of the base class to string array";
+
+               static readonly string errSimple2 = "Cannot serialize object of type '{0}'. " +
+                       "Consider changing type of XmlText member '{1}' from '{2}' to string or string array";
 
                #region Constructors
 
@@ -89,6 +93,8 @@ namespace System.Xml.Serialization {
                        XmlMembersMapping mps = new XmlMembersMapping (elementName, ns, hasWrapperElement, false, mapping);
                        mps.RelatedMaps = relatedMaps;
                        mps.Format = SerializationFormat.Literal;
+                       mps.Source = new MembersSerializationSource (elementName, hasWrapperElement, members, false, true, ns, includedTypes);
+                       if (allowPrivateTypes) mps.Source.CanBeGenerated = false;
                        return mps;
                }
 
@@ -133,6 +139,8 @@ namespace System.Xml.Serialization {
 
                        map.RelatedMaps = relatedMaps;
                        map.Format = SerializationFormat.Literal;
+                       map.Source = new XmlTypeSerializationSource (type, root, attributeOverrides, defaultNamespace, includedTypes);
+                       if (allowPrivateTypes) map.Source.CanBeGenerated = false;
                        return map;
                }
 
@@ -241,20 +249,46 @@ namespace System.Xml.Serialization {
                        {
                                XmlTypeMapping bmap = ImportClassMapping (type.BaseType, root, defaultNamespace);
                                
-                               if (type.BaseType != typeof (object))
+                               if (type.BaseType != typeof (object)) {
                                        map.BaseMap = bmap;
+                                       classMap.SetCanBeSimpleType (false);
+                               }
                                
                                // At this point, derived classes of this map must be already registered
                                
-                               bmap.DerivedTypes.Add (map);
-                               bmap.DerivedTypes.AddRange (map.DerivedTypes);
+                               RegisterDerivedMap (bmap, map);
                                
                                if (((ClassMap)bmap.ObjectMap).HasSimpleContent && classMap.ElementMembers != null && classMap.ElementMembers.Count != 1)
                                        throw new InvalidOperationException (String.Format (errSimple, map.TypeData.TypeName, map.BaseMap.TypeData.TypeName));
                        }
                        
+                       if (classMap.XmlTextCollector != null && !classMap.HasSimpleContent)
+                       {
+                               XmlTypeMapMember mem = classMap.XmlTextCollector;
+                               if (mem.TypeData.Type != typeof(string) && 
+                                  mem.TypeData.Type != typeof(string[]) && 
+                                  mem.TypeData.Type != typeof(object[]) && 
+                                  mem.TypeData.Type != typeof(XmlNode[]))
+                                  
+                                       throw new InvalidOperationException (String.Format (errSimple2, map.TypeData.TypeName, mem.Name, mem.TypeData.TypeName));
+                       }
+                       
                        return map;
                }
+               
+               void RegisterDerivedMap (XmlTypeMapping map, XmlTypeMapping derivedMap)
+               {
+                       map.DerivedTypes.Add (derivedMap);
+                       map.DerivedTypes.AddRange (derivedMap.DerivedTypes);
+                       
+                       if (map.BaseMap != null)
+                               RegisterDerivedMap (map.BaseMap, derivedMap);
+                       else {
+                               XmlTypeMapping obmap = ImportTypeMapping (typeof(object));
+                               if (obmap != map)
+                                       obmap.DerivedTypes.Add (derivedMap);
+                       }
+               }
 
                string GetTypeNamespace (TypeData typeData, XmlRootAttribute root, string defaultNamespace)
                {
@@ -479,32 +513,46 @@ namespace System.Xml.Serialization {
                        }
                }
 
-               public ICollection GetReflectionMembers (Type type)
+               ICollection GetReflectionMembers (Type type)
                {
                        ArrayList members = new ArrayList();
-                       PropertyInfo[] properties = type.GetProperties (BindingFlags.Instance | BindingFlags.Public);
-                       foreach (PropertyInfo prop in properties)
-                       {
-                               if (!prop.CanRead) continue;
-                               if (!prop.CanWrite && TypeTranslator.GetTypeData (prop.PropertyType).SchemaType != SchemaTypes.Array)
-                                       continue;
-                               if (prop.GetIndexParameters().Length > 0) continue;
-                                       
-                               XmlAttributes atts = attributeOverrides[type, prop.Name];
-                               if (atts == null) atts = new XmlAttributes (prop);
-                               if (atts.XmlIgnore) continue;
-                               XmlReflectionMember member = new XmlReflectionMember(prop.Name, prop.PropertyType, atts);
-                               members.Add (member);
-                       }
-
-                       FieldInfo[] fields = type.GetFields (BindingFlags.Instance | BindingFlags.Public);
-                       foreach (FieldInfo field in fields)
+                       MemberInfo[] tmembers = type.GetMembers (BindingFlags.Instance | BindingFlags.Public);
+                       int currentTypePos = 0;
+                       Type currentType = null;
+                       
+                       foreach (MemberInfo tmember in tmembers)
                        {
-                               XmlAttributes atts = attributeOverrides[type, field.Name];
-                               if (atts == null) atts = new XmlAttributes (field);
-                               if (atts.XmlIgnore) continue;
-                               XmlReflectionMember member = new XmlReflectionMember(field.Name, field.FieldType, atts);
-                               members.Add (member);
+                               if (currentType != tmember.DeclaringType)
+                               {
+                                       currentType = tmember.DeclaringType;
+                                       currentTypePos = 0;
+                               }
+                               
+                               if (tmember is FieldInfo)
+                               {
+                                       FieldInfo field = tmember as FieldInfo;
+                                       XmlAttributes atts = attributeOverrides[type, field.Name];
+                                       if (atts == null) atts = new XmlAttributes (field);
+                                       if (atts.XmlIgnore) continue;
+                                       XmlReflectionMember member = new XmlReflectionMember(field.Name, field.FieldType, atts);
+                                       members.Insert (currentTypePos, member);
+                                       currentTypePos++;
+                               }
+                               else if (tmember is PropertyInfo)
+                               {
+                                       PropertyInfo prop  = tmember as PropertyInfo;
+                                       if (!prop.CanRead) continue;
+                                       if (!prop.CanWrite && TypeTranslator.GetTypeData (prop.PropertyType).SchemaType != SchemaTypes.Array)
+                                               continue;
+                                       if (prop.GetIndexParameters().Length > 0) continue;
+                                               
+                                       XmlAttributes atts = attributeOverrides[type, prop.Name];
+                                       if (atts == null) atts = new XmlAttributes (prop);
+                                       if (atts.XmlIgnore) continue;
+                                       XmlReflectionMember member = new XmlReflectionMember(prop.Name, prop.PropertyType, atts);
+                                       members.Insert (currentTypePos, member);
+                                       currentTypePos++;
+                               }
                        }
                        return members;
                }
@@ -532,7 +580,7 @@ namespace System.Xml.Serialization {
                                         (rmember.MemberType.FullName == "System.Xml.XmlElement"))
                                {
                                        XmlTypeMapMemberAnyElement member = new XmlTypeMapMemberAnyElement();
-                                       member.ElementInfo = ImportAnyElementInfo (defaultNamespace, rmember.MemberType, member, atts);
+                                       member.ElementInfo = ImportAnyElementInfo (defaultNamespace, rmember, member, atts);
                                        mapMember = member;
                                }
                                else
@@ -556,11 +604,25 @@ namespace System.Xml.Serialization {
                                else 
                                        mapAttribute.AttributeName = atts.XmlAttribute.AttributeName;
 
-                               mapAttribute.Form = atts.XmlAttribute.Form;
-                               mapAttribute.Namespace = (atts.XmlAttribute.Namespace != null) ? atts.XmlAttribute.Namespace : "";
                                if (typeData.IsComplexType)
                                        mapAttribute.MappedType = ImportTypeMapping (typeData.Type, null, mapAttribute.Namespace);
-
+                               
+                               if (atts.XmlAttribute.Namespace != null && atts.XmlAttribute.Namespace != defaultNamespace)
+                               {
+                                       if (atts.XmlAttribute.Form == XmlSchemaForm.Unqualified)
+                                               throw new InvalidOperationException ("The Form property may not be 'Unqualified' when an explicit Namespace property is present");
+                                       mapAttribute.Form = XmlSchemaForm.Qualified;
+                                       mapAttribute.Namespace = atts.XmlAttribute.Namespace;
+                               }
+                               else
+                               {
+                                       mapAttribute.Form = atts.XmlAttribute.Form;
+                                       if (atts.XmlAttribute.Form == XmlSchemaForm.Qualified)
+                                               mapAttribute.Namespace = defaultNamespace;
+                                       else
+                                               mapAttribute.Namespace = "";
+                               }
+                               
                                typeData = TypeTranslator.GetTypeData(rmember.MemberType, atts.XmlAttribute.DataType);
                                mapMember = mapAttribute;
                        }
@@ -595,6 +657,8 @@ namespace System.Xml.Serialization {
                                        elem.Namespace = (atts.XmlArray != null && atts.XmlArray.Namespace != null) ? atts.XmlArray.Namespace : defaultNamespace;
                                        elem.MappedType = ImportListMapping (rmember.MemberType, null, elem.Namespace, atts, 0);
                                        elem.IsNullable = (atts.XmlArray != null) ? atts.XmlArray.IsNullable : false;
+                                       elem.Form = (atts.XmlArray != null) ? atts.XmlArray.Form : XmlSchemaForm.Qualified;
+
                                        member.ElementInfo.Add (elem);
                                        mapMember = member;
                                }
@@ -641,7 +705,7 @@ namespace System.Xml.Serialization {
                                elem.IsNullable = att.IsNullable;
                                
                                if (elem.IsNullable && elem.TypeData.IsValueType)
-                                       throw new InvalidOperationException ("IsNullable may not be 'true' for value type " + elem.TypeData.FullTypeName);
+                                       throw new InvalidOperationException ("IsNullable may not be 'true' for value type " + elem.TypeData.FullTypeName + " in member '" + defaultName + "'");
                                        
                                if (elem.TypeData.IsComplexType)
                                {
@@ -663,18 +727,27 @@ namespace System.Xml.Serialization {
                        return list;
                }
 
-               XmlTypeMapElementInfoList ImportAnyElementInfo (string defaultNamespace, Type defaultType, XmlTypeMapMemberElement member, XmlAttributes atts)
+               XmlTypeMapElementInfoList ImportAnyElementInfo (string defaultNamespace, XmlReflectionMember rmember, XmlTypeMapMemberElement member, XmlAttributes atts)
                {
                        XmlTypeMapElementInfoList list = new XmlTypeMapElementInfoList();
 
-                       ImportTextElementInfo (list, defaultType, member, atts);
+                       ImportTextElementInfo (list, rmember.MemberType, member, atts);
 
                        foreach (XmlAnyElementAttribute att in atts.XmlAnyElements)
                        {
                                XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (member, TypeTranslator.GetTypeData(typeof(XmlElement)));
-                               if (att.Name != null && att.Name != string.Empty) elem.ElementName = att.Name;
-                               else elem.IsUnnamedAnyElement = true;
-                               elem.Namespace = (att.Namespace != null) ? att.Namespace : "";
+                               if (att.Name != null && att.Name != string.Empty) 
+                               {
+                                       elem.ElementName = att.Name;
+                                       elem.Namespace = (att.Namespace != null) ? att.Namespace : "";
+                               }
+                               else 
+                               {
+                                       elem.IsUnnamedAnyElement = true;
+                                       elem.Namespace = defaultNamespace;
+                                       if (att.Namespace != null) 
+                                               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.");
+                               }
                                list.Add (elem);
                        }
                        return list;
@@ -714,7 +787,15 @@ namespace System.Xml.Serialization {
                                throw new ArgumentNullException ("type");
 
                        if (includedTypes == null) includedTypes = new ArrayList ();
-                       includedTypes.Add (type);
+                       if (!includedTypes.Contains (type))
+                               includedTypes.Add (type);
+               }
+
+               public void IncludeTypes (ICustomAttributeProvider provider)
+               { 
+                       object[] ats = provider.GetCustomAttributes (typeof(XmlIncludeAttribute), true);
+                       foreach (XmlIncludeAttribute at in ats)
+                               IncludeType (at.Type);
                }
 
                #endregion // Methods