Skip to content

Commit

Permalink
Fixed namespace resolution bug in migration extension (#518)
Browse files Browse the repository at this point in the history
  • Loading branch information
Mike-E-angelo authored Mar 30, 2021
1 parent 84dc8d5 commit 86c603a
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@

namespace ExtendedXmlSerializer.ExtensionModel.Xml
{
sealed class FormatReaderContexts : ReferenceCacheBase<System.Xml.XmlReader, IFormatReaderContext>,
IFormatReaderContexts
sealed class FormatReaderContexts
: ReferenceCacheBase<System.Xml.XmlReader, IFormatReaderContext>,
IFormatReaderContexts
{
readonly IIdentityStore _store;
readonly IXmlParserContexts _contexts;
Expand All @@ -28,17 +29,19 @@ static XmlNamespaceManager Default(System.Xml.XmlReader parameter)

protected override IFormatReaderContext Create(System.Xml.XmlReader parameter)
{
var resolver = _contexts.IsSatisfiedBy(parameter.NameTable)
? _contexts.Get(parameter.NameTable)
.NamespaceManager
: parameter as IXmlNamespaceResolver ?? Default(parameter);
var mapper = new IdentityMapper(_store, resolver);
var resolver = Determine(parameter) ?? parameter as IXmlNamespaceResolver ?? Default(parameter);
var mapper = new IdentityMapper(_store, resolver);

var reflector = new TypePartReflector(mapper, _types);
var types = new TypeParser(reflector);
var parser = new ReflectionParser(types, reflector);
var result = new FormatReaderContext(mapper, parser);
return result;
}

IXmlNamespaceResolver Determine(System.Xml.XmlReader parameter)
=> parameter.NameTable != null && _contexts.IsSatisfiedBy(parameter.NameTable)
? _contexts.Get(parameter.NameTable).NamespaceManager
: null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using ExtendedXmlSerializer.ContentModel.Properties;
using ExtendedXmlSerializer.ContentModel.Reflection;
using ExtendedXmlSerializer.Core;
using ExtendedXmlSerializer.Core.Parsing;
using ExtendedXmlSerializer.Core.Sources;
using ExtendedXmlSerializer.ReflectionModel;
using System;
Expand Down Expand Up @@ -96,7 +97,7 @@ public IFormatReader Get(IFormatReader parameter)

if (version > _version)
{
throw new XmlException($"Unknown varsion number {version} for type {typeInfo}.");
throw new XmlException($"Unknown version number {version} for type {typeInfo}.");
}

parameter.Set();
Expand All @@ -110,14 +111,44 @@ public IFormatReader Get(IFormatReader parameter)
if (migration == null)
throw new XmlException(
$"Migrations for type {fullName} contains invalid migration at index {i}.");
_migrations[index]
.Invoke(element);
_migrations[index](element);
}

var xmlReader = element.CreateReader();
XmlParserContexts.Default.Assign(xmlReader.NameTable,
XmlParserContexts.Default.Get(reader.NameTable));
var result = _factory.Get(xmlReader);
var attributes = element.Descendants()
.Attributes()
.Where(a => a.IsNamespaceDeclaration)
.Distinct()
.ToArray();
foreach (var attribute in attributes)
{
if (element.Attribute(attribute.Name) == null)
{
element.Add(attribute);
}
}

var native = element.CreateReader(ReaderOptions.OmitDuplicateNamespaces);
var context = XmlParserContexts.Default.Get(reader.NameTable);
if (reader.NameTable != null)
{
var manager = context.NamespaceManager;

foreach (var attribute in attributes)
{
var prefix = attribute.Name.LocalName;
if (manager.LookupNamespace(prefix) == null)
{
var @namespace = element.GetNamespaceOfPrefix(prefix);
if (@namespace != null)
{
manager.AddNamespace(prefix, @namespace.NamespaceName);
}
}
}
}

XmlParserContexts.Default.Assign(native.NameTable, context);
var result = _factory.Get(native);
AssociatedReaders.Default.Assign(result, parameter);
return result;
}
Expand Down
57 changes: 57 additions & 0 deletions test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue517Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using ExtendedXmlSerializer.Configuration;
using ExtendedXmlSerializer.Tests.ReportedIssues.Shared.Issue517;
using ExtendedXmlSerializer.Tests.ReportedIssues.Support;
using FluentAssertions;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Xml.Linq;
using Xunit;

namespace ExtendedXmlSerializer.Tests.ReportedIssues
{
public sealed class Issue517Tests
{
[Fact]
public void Verify()
{
var instance = new Class1 { obj = new Class2() };

var sut = new ConfigurationContainer().Type<Class1>()
.AddMigration(new EmptyMigration())
.Create()
.ForTesting();

sut.Cycle(instance).Should().BeEquivalentTo(instance);
}

[Fact]
public void VerifyAdditional()
{
var container = new Shared.Issue517.ContainerNameSpace.Container();
for (int i = 0; i < 1; i++)
{
container.Childrens.Add(new Shared.Issue517.ItemNameSpace.Item());
}

IConfigurationContainer config = new ConfigurationContainer();
config.Type<Shared.Issue517.ContainerNameSpace.Container>().AddMigration(new EmptyMigration());
var serializer = config.Create().ForTesting();

serializer.Cycle(container).Should().BeEquivalentTo(container);

}

public class EmptyMigration : IEnumerable<Action<XElement>>
{
public IEnumerator<Action<XElement>> GetEnumerator()
{
yield return x => {}; //Do nothing
}

IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

class Class2 : Interface1 {}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System.Collections.Generic;

namespace ExtendedXmlSerializer.Tests.ReportedIssues.Shared.Issue517
{
class ItemContainer
{

public List<Class1> Items { get; set; } = new List<Class1>();

}

class Class1
{

public Interface1 obj { get; set; }
}

interface Interface1 { }

namespace ContainerNameSpace
{
class Container
{
public List<ItemNameSpace.Item> Childrens { get; set; } = new List<ItemNameSpace.Item>();
}
}

namespace ItemNameSpace
{
class Item { }
}

}

0 comments on commit 86c603a

Please sign in to comment.