Skip to content

Commit

Permalink
Handle soap attributes. #3
Browse files Browse the repository at this point in the history
  • Loading branch information
JohanLarsson committed Sep 10, 2018
1 parent 2e9628a commit 7bba70d
Show file tree
Hide file tree
Showing 5 changed files with 232 additions and 35 deletions.
20 changes: 19 additions & 1 deletion Gu.Xml.Tests/Helpers/Reference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,33 @@ public static class Reference
{
public static string XmlSerializer(object value)
{
var sb = new StringBuilder();
var serializer = new XmlSerializer(value.GetType());
var sb = new StringBuilder();
using (var writer = new StringWriter(sb))
{
serializer.Serialize(writer, value);
}

return sb.Replace("utf-16", "utf-8")
.Replace(" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"", string.Empty)
.Replace(" xsi:type=\"xsd:boolean\"", string.Empty)
.Replace(" xsi:type=\"xsd:int\"", string.Empty)
.ToString();
}

public static string XmlSerializerSoap(object value)
{
var myMapping = new SoapReflectionImporter().ImportTypeMapping(value.GetType());
var serializer = new XmlSerializer(myMapping);
var sb = new StringBuilder();
using (var writer = new StringWriter(sb))
{
serializer.Serialize(writer, value);
}

return sb.Replace("utf-16", "utf-8")
.Replace(" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"", string.Empty)
.Replace(" id=\"id1\"", string.Empty)
.Replace(" xsi:type=\"xsd:boolean\"", string.Empty)
.Replace(" xsi:type=\"xsd:int\"", string.Empty)
.ToString();
Expand Down
142 changes: 142 additions & 0 deletions Gu.Xml.Tests/XmlTests.SerializeWithSoapAttributes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
namespace Gu.Xml.Tests
{
using System;
using System.Diagnostics;
using System.Xml.Serialization;
using NUnit.Framework;

public partial class XmlTests
{
public class SerializeWithSoapAttributes
{
private static readonly TestCaseData[] Values =
{
new TestCaseData(new WithSoapTypeAttribute { Value = 1 }),
new TestCaseData(new WithSoapTypeAttributeExplicitName { Value = 1 }),
new TestCaseData(new PropertyWithSoapIgnoreAttribute {Value = 1}),
new TestCaseData(new PropertyWithSoapElementAttribute { Value = 1 }),
new TestCaseData(new PropertyWithSoapElementAttributeExplicitName { Value = 1 }),
new TestCaseData(new PropertyWithSoapAttributeAttribute { Value = 1 }),
new TestCaseData(new PropertyWithSoapAttributeAttributeExplicitName { Value = 1 }),
new TestCaseData(new ExplicitInterfaceWithSoapElementAttribute()),
new TestCaseData(new FieldWithSoapIgnoreAttribute {Value = 1}),
new TestCaseData(new FieldWithSoapElementAttribute { Value = 1 }),
new TestCaseData(new FieldWithSoapElementAttributeExplicitName { Value = 1 }),
new TestCaseData(new FieldWithSoapAttributeAttribute { Value = 1 }),
new TestCaseData(new FieldWithSoapAttributeAttributeExplicitName { Value = 1 }),
};

[TestCaseSource(nameof(Values))]
public void Serialize(object value)
{
var expected = Reference.XmlSerializerSoap(value);
var actual = Xml.Serialize(value);
if (actual == expected)
{
if (Debugger.IsAttached)
{
Console.WriteLine(expected);
}

return;
}

Console.WriteLine("Expected:");
Console.Write(expected);
Console.WriteLine();
Console.WriteLine();

Console.WriteLine("Actual:");
Console.Write(actual);
Console.WriteLine();
Console.WriteLine();

Assert.AreEqual(expected, actual);
}

[SoapType]
public class WithSoapTypeAttribute
{
public int Value { get; set; } = 1;
}

[SoapType("Name")]
public class WithSoapTypeAttributeExplicitName
{
public int Value { get; set; } = 1;
}

public class PropertyWithSoapElementAttribute
{
[SoapElement]
public int Value { get; set; }
}

public class PropertyWithSoapElementAttributeExplicitName
{
[SoapElement("Name")]
public int Value { get; set; }
}

public class FieldWithSoapElementAttribute
{
[SoapElement]
public int Value = 1;
}

public class FieldWithSoapElementAttributeExplicitName
{
[SoapElement("Name")]
public int Value = 1;
}

public interface IValue
{
// ReSharper disable once UnusedMember.Global
int Value { get; set; }
}

public class ExplicitInterfaceWithSoapElementAttribute : IValue
{
[SoapElement]
int IValue.Value { get; set; }
}

public class PropertyWithSoapAttributeAttribute
{
[SoapAttribute]
public int Value { get; set; }
}

public class PropertyWithSoapAttributeAttributeExplicitName
{
[SoapAttribute("Name")]
public int Value { get; set; }
}

public class FieldWithSoapAttributeAttribute
{
[SoapAttribute]
public int Value;
}

public class FieldWithSoapAttributeAttributeExplicitName
{
[SoapAttribute("Name")]
public int Value;
}

public class PropertyWithSoapIgnoreAttribute
{
[SoapIgnore]
public int Value { get; set; }
}

public class FieldWithSoapIgnoreAttribute
{
[SoapIgnore]
public int Value { get; set; }
}
}
}
}
7 changes: 7 additions & 0 deletions Gu.Xml/Internals/RootName.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ xmlRoot.ElementName is string elementName &&
return elementName;
}

if (Attribute.GetCustomAttribute(type, typeof(SoapTypeAttribute)) is SoapTypeAttribute soapType &&
soapType.TypeName is string typeName &&
!string.IsNullOrEmpty(typeName))
{
return typeName;
}

if (!type.IsGenericType &&
!type.HasElementType)
{
Expand Down
31 changes: 27 additions & 4 deletions Gu.Xml/Writers/AttributeWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@ public AttributeWriter(string name)

public static bool TryCreate(PropertyInfo property, out AttributeWriter writer)
{
if (Attribute.GetCustomAttribute(property, typeof(XmlAttributeAttribute)) is XmlAttributeAttribute attribute)
if (TryGetAttributeName(property, out var name))
{
var name = string.IsNullOrEmpty(attribute.AttributeName) ? property.Name : attribute.AttributeName;
writer = (AttributeWriter)typeof(AttributeWriter)
.GetMethod(nameof(CreateWriter), BindingFlags.Static | BindingFlags.NonPublic)
.MakeGenericMethod(property.ReflectedType, property.PropertyType)
Expand All @@ -32,9 +31,8 @@ public static bool TryCreate(PropertyInfo property, out AttributeWriter writer)

public static bool TryCreate(FieldInfo field, out AttributeWriter writer)
{
if (Attribute.GetCustomAttribute(field, typeof(XmlAttributeAttribute)) is XmlAttributeAttribute attribute)
if (TryGetAttributeName(field, out var name))
{
var name = string.IsNullOrEmpty(attribute.AttributeName) ? field.Name : attribute.AttributeName;
writer = (AttributeWriter)typeof(AttributeWriter)
.GetMethod(nameof(CreateWriter), BindingFlags.Static | BindingFlags.NonPublic)
.MakeGenericMethod(field.ReflectedType, field.FieldType)
Expand All @@ -60,5 +58,30 @@ private static AttributeWriter<TSource, TValue> CreateWriter<TSource, TValue>(st
throw new InvalidOperationException($"Not handling {member}. Bug in Gu.Xml.");
}
}

private static bool TryGetAttributeName(MemberInfo member, out string name)
{
name = null;
if (Attribute.GetCustomAttribute(member, typeof(XmlAttributeAttribute)) is XmlAttributeAttribute xmlAttribute)
{
name = xmlAttribute.AttributeName ?? string.Empty;
}
else if (Attribute.GetCustomAttribute(member, typeof(SoapAttributeAttribute)) is SoapAttributeAttribute soapAttribute)
{
name = soapAttribute.AttributeName ?? string.Empty;
}

if (name == null)
{
return false;
}

if (name == string.Empty)
{
name = member.Name;
}

return true;
}
}
}
67 changes: 37 additions & 30 deletions Gu.Xml/Writers/ElementWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,12 @@ public static bool TryCreate(PropertyInfo property, out ElementWriter writer)
!getMethod.IsPrivate &&
!getMethod.IsFamily &&
!IsIgnoredCalculated() &&
Attribute.GetCustomAttribute(property, typeof(XmlIgnoreAttribute)) == null &&
Attribute.GetCustomAttribute(property, typeof(XmlAttributeAttribute)) == null)
TryGetElementName(property, out var name))
{
writer = (ElementWriter)typeof(ElementWriter)
.GetMethod(nameof(CreateWriter), BindingFlags.Static | BindingFlags.NonPublic)
.MakeGenericMethod(property.ReflectedType, property.PropertyType)
.Invoke(null, new object[] { Name(), property });
.Invoke(null, new object[] { name, property });
return true;
}

Expand All @@ -41,49 +40,24 @@ bool IsIgnoredCalculated()
Attribute.GetCustomAttribute(property.GetMethod, typeof(CompilerGeneratedAttribute)) == null &&
Attribute.GetCustomAttribute(property.GetMethod, typeof(XmlElementAttribute)) == null;
}

string Name()
{
if (Attribute.GetCustomAttribute(property, typeof(XmlElementAttribute)) is XmlElementAttribute xmlElement &&
xmlElement.ElementName is string name &&
!string.IsNullOrEmpty(name))
{
return name;
}

return property.Name;
}
}

public static bool TryCreate(FieldInfo field, out ElementWriter writer)
{
if (!field.IsStatic &&
!field.IsPrivate &&
!field.IsFamily &&
Attribute.GetCustomAttribute(field, typeof(XmlIgnoreAttribute)) == null &&
Attribute.GetCustomAttribute(field, typeof(XmlAttributeAttribute)) == null)
TryGetElementName(field, out var name))
{
writer = (ElementWriter)typeof(ElementWriter)
.GetMethod(nameof(CreateWriter), BindingFlags.Static | BindingFlags.NonPublic)
.MakeGenericMethod(field.ReflectedType, field.FieldType)
.Invoke(null, new object[] { Name(), field });
.Invoke(null, new object[] { name, field });
return true;
}

writer = null;
return false;

string Name()
{
if (Attribute.GetCustomAttribute(field, typeof(XmlElementAttribute)) is XmlElementAttribute xmlElement &&
xmlElement.ElementName is string name &&
!string.IsNullOrEmpty(name))
{
return name;
}

return field.Name;
}
}

public abstract void Write<T>(XmlWriter writer, T source);
Expand All @@ -100,5 +74,38 @@ private static ElementWriter<TSource, TValue> CreateWriter<TSource, TValue>(stri
throw new InvalidOperationException($"Not handling {member}. Bug in Gu.Xml.");
}
}

private static bool TryGetElementName(MemberInfo member, out string name)
{
name = null;
if (Attribute.GetCustomAttribute(member, typeof(XmlElementAttribute)) is XmlElementAttribute xmlAttribute)
{
name = xmlAttribute.ElementName ?? string.Empty;
}
else if (Attribute.GetCustomAttribute(member, typeof(SoapElementAttribute)) is SoapElementAttribute soapAttribute)
{
name = soapAttribute.ElementName ?? string.Empty;
}

if (name == null)
{
if (Attribute.GetCustomAttribute(member, typeof(XmlIgnoreAttribute)) != null ||
Attribute.GetCustomAttribute(member, typeof(XmlAttributeAttribute)) != null ||
Attribute.GetCustomAttribute(member, typeof(SoapIgnoreAttribute)) != null ||
Attribute.GetCustomAttribute(member, typeof(SoapAttributeAttribute)) != null)
{
return false;
}

name = member.Name;
}

if (name == string.Empty)
{
name = member.Name;
}

return true;
}
}
}

0 comments on commit 7bba70d

Please sign in to comment.