Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[System.Xml] Fix deserialization issue (#16965)
[This ](https://github.com/mono/mono/pull/11194/files#diff-ae54d9565e735005686191de0f19ed50R431-R435)change in `XmlTypeMapElementInfo.GetElement`  introduced the logic for handling the case of derived types deserialization. 
For some cases (like #16918) it breaks existing functionality because it returns wrong element for given element name after searching withing derived types collection.

![image](https://user-images.githubusercontent.com/3258267/65416085-bedc0500-ddff-11e9-941c-f24045c64121.png)

Unfortunately, what I can do here is just reverting the related changes.

Fixes #16918
  • Loading branch information
MaximLipnin authored and akoeplinger committed Sep 24, 2019
1 parent 7e6d863 commit 9988ebc
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 183 deletions.
Expand Up @@ -204,9 +204,11 @@ protected virtual object ReadClassInstance (XmlTypeMapping typeMap, bool isNulla
{
if (isNullable && ReadNull()) return null;

if (checkType) {
System.Xml.XmlQualifiedName t = GetXsiType();
if (t != null) {
if (checkType)
{
System.Xml.XmlQualifiedName t = GetXsiType();
if (t != null)
{
XmlTypeMapping realMap = typeMap.GetRealElementMap (t.Name, t.Namespace);
if (realMap == null) {
if (typeMap.TypeData.Type == typeof(object))
Expand All @@ -219,12 +221,7 @@ protected virtual object ReadClassInstance (XmlTypeMapping typeMap, bool isNulla
}
else if (typeMap.TypeData.Type == typeof(object))
return ReadTypedPrimitive (AnyType);
else {
XmlTypeMapping realMap = typeMap.GetRealElementMap (Reader.LocalName, Reader.NamespaceURI);
if (realMap != null && realMap != typeMap)
return ReadObject(realMap, false, false);
}
}
}

object ob = CreateInstance (typeMap.TypeData.Type, true);

Expand Down
24 changes: 4 additions & 20 deletions mcs/class/System.XML/System.Xml.Serialization/XmlTypeMapping.cs
Expand Up @@ -389,7 +389,7 @@ public XmlTypeMapMemberAttribute GetAttribute (string name, string ns)
return (XmlTypeMapMemberAttribute)_attributeMembers [BuildKey (name,ns, -1)];
}

public XmlTypeMapElementInfo GetElement (string name, string ns, int minimalOrder)
public XmlTypeMapElementInfo GetElement(string name, string ns, int minimalOrder)
{
if (_elements == null)
return null;
Expand All @@ -404,38 +404,22 @@ public XmlTypeMapElementInfo GetElement (string name, string ns, int minimalOrde
selected = info;
}
}
else if (info.MappedType != null && info.MappedType.DerivedTypes.Count > 0) {
foreach (XmlTypeMapping derrivedInfo in info.MappedType.DerivedTypes) {
if (derrivedInfo.ElementName == name && derrivedInfo.Namespace == ns) {
if (info.ExplicitOrder < minimalOrder)
continue;

if (selected == null || selected.ExplicitOrder > info.ExplicitOrder) {
selected = info;
}
}
}
}
}

return selected;
}

public XmlTypeMapElementInfo GetElement (string name, string ns)
public XmlTypeMapElementInfo GetElement(string name, string ns)
{
if (_elements == null) return null;

foreach (XmlTypeMapElementInfo info in _elements.Values)
if (info.ElementName == name && info.Namespace == ns)
return info;
else if (info.MappedType != null && info.MappedType.DerivedTypes.Count > 0) {
foreach (XmlTypeMapping derrivedInfo in info.MappedType.DerivedTypes)
if (derrivedInfo.ElementName == name && derrivedInfo.Namespace == ns)
return info;
}

return null;
}

public XmlTypeMapElementInfo GetElement (int index)
{
if (_elements == null) return null;
Expand Down
Expand Up @@ -14,6 +14,7 @@
using System;
using System.Globalization;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using NUnit.Framework;
Expand Down Expand Up @@ -1686,28 +1687,40 @@ public void TestOrderedMapWithFlatList ()
Assert.AreEqual ("b", d.Extra[1]);
}

[Test] // PR #11194
public void TestDerrivedClassProperty ()
// https://github.com/mono/mono/issues/16918
[Test]
public void Bug16918 ()
{
var data = "<layout width=\".25\" height =\".25\" x=\"0\" y=\"0\" id=\"portrait\" class=\"render\"><background color=\"white\"><div x=\".03\" y=\".05\" width=\".94\" height =\".9\" layout=\"proportional_rows\" paddingX=\".01\" paddingY=\".02\"><background color=\"black\"></background><background color=\"gray\" padding=\".1\"><label color=\"white\" font=\"emulogic.ttf\" fontSize=\"15\">Test UI</label></background><br brSize=\"1\" /><background class=\"back,Lab\" color=\"green\"><label class=\"Lab\" color=\"white\" font=\"emulogic.ttf\" fontSize=\"15\">GREEN</label></background><background color=\"red\"><label class=\"Lab\" color=\"white\" font=\"emulogic.ttf\" fontSize=\"15\">RED</label></background><background color=\"blue\"><label class=\"Lab\" color=\"white\" font=\"emulogic.ttf\" fontSize=\"15\">TLUE</label></background><background color=\"blue\"><label class=\"Lab\" color=\"white\" font=\"emulogic.ttf\" fontSize=\"15\">BLUE</label></background></div></background></layout>";

XmlAttributeOverrides overrides = PR11194.GenerateLayoutOverrides<PR11194ChildLo>();
PropertiesWithSameNameAsTheirType testObject = new PropertiesWithSameNameAsTheirType ()
{
E1 = E1.Two,
E2 = E2.Two,
E3 = E3.Two,
E4 = E4.Two,
E5 = E5.Two
};

XmlSerializer serializer = new XmlSerializer (typeof (PropertiesWithSameNameAsTheirType));

// serialize
string serializedObject;
using (MemoryStream memoryStream = new MemoryStream ())
{
serializer.Serialize (memoryStream, testObject);
serializedObject = Encoding.UTF8.GetString (memoryStream.ToArray ());
}

var result = Deserialize(typeof(PR11194ChildLo), data, overrides) as PR11194ChildLo;
PropertiesWithSameNameAsTheirType deserializedObject;
using (MemoryStream memoryStream = new MemoryStream (Encoding.UTF8.GetBytes (serializedObject)))
{
deserializedObject = (PropertiesWithSameNameAsTheirType)serializer.Deserialize (memoryStream);
}

PR11194Parent2 child;
Assert.IsNotNull(result, "#11194_1");
Assert.AreEqual(1, result.children.Count, "#11194_2");
child = result.children[0] as PR11194Parent2;
Assert.IsNotNull(child, "#11194_3");
Assert.AreEqual(1, child.children.Count, "#11194_4");
child = child.children[0] as PR11194Parent2;
Assert.IsNotNull(child, "#11194_5");
Assert.AreEqual(7, child.children.Count, "#11194_6");
child = child.children[1] as PR11194Parent2;
Assert.IsNotNull(child, "#11194_7");
Assert.AreEqual(1, child.children.Count, "#11194_8");
Assert.AreEqual("PR11194ChildL", child.children[0].GetType().Name, "#11194_9");
Assert.AreEqual (testObject.E1, deserializedObject.E1, "#1");
Assert.AreEqual (testObject.E2, deserializedObject.E2, "#2");
Assert.AreEqual (testObject.E3, deserializedObject.E3, "#3");
Assert.AreEqual (testObject.E4, deserializedObject.E4, "#4");
Assert.AreEqual (testObject.E5, deserializedObject.E5, "#5");
}
}
}
Expand Up @@ -12,8 +12,6 @@
//

using System;
using System.Linq;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
Expand Down Expand Up @@ -1207,157 +1205,54 @@ public sealed class ClassWithDefaultTextNotNull
}
}


#region PR_11194

#region PR_11194_GenerateOverrides
public static class PR11194
{
public static XmlAttributeOverrides GenerateLayoutOverrides<T>()
{
Type tType = typeof(T);

TypeInfo tTypeInfo = tType.GetTypeInfo();

IEnumerable<PropertyInfo> props = tType.GetRuntimeProperties();

XmlAttributeOverrides overrides = new XmlAttributeOverrides();

foreach (PropertyInfo prop in props) {
XmlDerrivedAttribute attr = prop.GetCustomAttribute<XmlDerrivedAttribute>();

if (attr == null) {
continue;
}

Type dType = prop.DeclaringType;

Type pType = prop.PropertyType;
TypeInfo pTypeInfo = pType.GetTypeInfo();

Type enumType = typeof(IEnumerable<>);

if (pTypeInfo.IsGenericType
&& pTypeInfo.ImplementedInterfaces.Any(t =>
(t.GetTypeInfo().IsGenericType && t.GetGenericTypeDefinition() == enumType))) {
pType = pType.GenericTypeArguments[0];
}

XmlAttributes overrideAttributes = GenerateOverrideAttributes(dType, pType, attr);

overrides.Add(dType, prop.Name, overrideAttributes);
}

return overrides;
}

private static XmlAttributes GenerateOverrideAttributes (Type declaringType, Type propertyType, XmlDerrivedAttribute attr)
{
XmlAttributes xAttrs = new XmlAttributes();

Assembly a = declaringType.GetTypeInfo().Assembly;
TypeInfo interfaceType = propertyType.GetTypeInfo();
IEnumerable<Type> types = a.ExportedTypes.Where(t => interfaceType.IsAssignableFrom(t.GetTypeInfo()) && !t.GetTypeInfo().IsAbstract);

foreach (Type t in types) {
string name = NameBySourceType(t, attr.SrcType);// t.GetTypeInfo().GetCustomAttribute<XmlTypeAttribute>().TypeName;
XmlElementAttribute xAttr = new XmlElementAttribute();
xAttr.ElementName = name;
xAttr.Type = t;
xAttrs.XmlElements.Add(xAttr);
}

return xAttrs;
}

private static string NameBySourceType (Type derrivedType, XmlDerrivedSourceType srcType)
{
string name = null;
switch (srcType)
{
case XmlDerrivedSourceType.ByXmlType:
name = derrivedType.GetTypeInfo().GetCustomAttribute<XmlTypeAttribute>().TypeName;
break;
}
return name;
}
}
#endregion

#region helperAttribute
public enum XmlDerrivedSourceType
{
ByXmlType
}

public class XmlDerrivedAttribute : Attribute
[Serializable]
public class PropertiesWithSameNameAsTheirType
{
public XmlDerrivedSourceType SrcType { get; set; }

public XmlDerrivedAttribute(XmlDerrivedSourceType srcType)
public PropertiesWithSameNameAsTheirType ()
{
SrcType = srcType;
}
}
#endregion

public abstract class PR11194Parent
{
[XmlIgnore]
public PR11194Parent Parent { get; set; }
}
public object obj1 { get; set; }
public object obj2 { get; set; }
public object obj3 { get; set; }
public object obj4 { get; set; }
public object obj5 { get; set; }

public abstract class PR11194Parent2 : PR11194Parent
{
[XmlAttribute]
public float width { get; set; }
[XmlAttribute]
public float height { get; set; }
[XmlAttribute]
public float x { get; set; }
[XmlAttribute]
public float y { get; set; }
[XmlAttribute]
public string id { get; set; }
[XmlElement]
[XmlDerrived(XmlDerrivedSourceType.ByXmlType)]
public List<PR11194Parent> children { get; set; }
public E1 E1 { get; set; }
public E2 E2 { get; set; }
public E3 E3 { get; set; }
public E4 E4 { get; set; }
public E5 E5 { get; set; }
}

[XmlType("background")]
public class PR11194ChildB : PR11194Parent2
public enum E1
{
[XmlAttribute]
public string image { get; set; }
One,
Two,
}

[XmlType("br")]
public class PR11194ChildBr : PR11194Parent
public enum E2
{
[XmlAttribute("brSize")]
public int breaks { get; set; }
One,
Two,
}

[XmlType("div")]
public class PR11194ChildD : PR11194ChildLo
public enum E5
{
One,
Two,
}

[XmlType("label")]
public class PR11194ChildL : PR11194Parent2
public enum E3
{
[XmlAttribute]
public string font { get; set; }
[XmlAttribute]
public int fontSize { get; set; }
[XmlText]
public string Text { get; set; }
One,
Two,
}

[XmlType("layout")]
public class PR11194ChildLo : PR11194Parent2
public enum E4
{
One,
Two,
}
#endregion
}

4 changes: 2 additions & 2 deletions sdks/ios/Makefile
Expand Up @@ -24,6 +24,7 @@ TEST_SUITES = \
System.Json \
System.ComponentModel.DataAnnotations \
System.Security \
System.Xml \
System.Xml.Linq \
System.ServiceModel.Web \
Mono.Data.Tds \
Expand All @@ -33,7 +34,6 @@ TEST_SUITES = \
TEST_SUITES_COMPILING = \
System \
System.Net.Http \
System.Xml \
Mono.CSharp

# Not compiling in monotouch profile
Expand Down Expand Up @@ -215,7 +215,7 @@ Mono.Data.Tds_ASSEMBLIES = $(BCL_DIR)/Mono.Data.Tds.dll $(TESTDIR)/monotouch_Mon
Mono.Data.Tds_ARGS = $(NUNIT) monotouch_Mono.Data.Tds_test.dll
System.Security_ASSEMBLIES = $(BCL_DIR)/System.Security.dll $(TESTDIR)/monotouch_System.Security_test.dll
System.Security_ARGS = $(NUNIT) monotouch_System.Security_test.dll
System.Xml_ASSEMBLIES = $(BCL_DIR)/System.Xml.dll $(TESTDIR)/monotouch_System.Xml_test.dll
System.Xml_ASSEMBLIES = $(BCL_DIR)/System.Data.dll $(TESTDIR)/monotouch_System.Xml_test.dll
System.Xml_ARGS = $(NUNIT) monotouch_System.Xml_test.dll
System.Xml.Linq_ASSEMBLIES = $(BCL_DIR)/System.Xml.Linq.dll $(TESTDIR)/monotouch_System.Xml.Linq_test.dll
System.Xml.Linq_ARGS = $(NUNIT) monotouch_System.Xml.Linq_test.dll
Expand Down

0 comments on commit 9988ebc

Please sign in to comment.