Skip to content

Commit

Permalink
- Adjusted SerializationInterceptionExtension to account for activate…
Browse files Browse the repository at this point in the history
…d types.

- Added support for a generalized interceptor.
  • Loading branch information
Mike-E-angelo committed Sep 21, 2020
1 parent 94151ad commit a00f7af
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 18 deletions.
9 changes: 2 additions & 7 deletions src/ExtendedXmlSerializer/ContentModel/RuntimeSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using ExtendedXmlSerializer.ContentModel.Format;
using ExtendedXmlSerializer.ContentModel.Reflection;
using JetBrains.Annotations;
using System.Reflection;

namespace ExtendedXmlSerializer.ContentModel
{
Expand All @@ -20,13 +19,9 @@ public RuntimeSerializer(IRuntimeSerialization serialization, IClassification cl

public void Write(IFormatWriter writer, object instance)
{
var typeInfo = instance.GetType()
.GetTypeInfo();
_serialization.Get(typeInfo)
.Write(writer, instance);
_serialization.Get(instance.GetType()).Write(writer, instance);
}

public object Get(IFormatReader reader) => _serialization.Get(_classification.Get(reader))
.Get(reader);
public object Get(IFormatReader reader) => _serialization.Get(_classification.Get(reader)).Get(reader);
}
}
15 changes: 14 additions & 1 deletion src/ExtendedXmlSerializer/ExtensionMethodsForContent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,21 @@ public static ITypeConfiguration<T> WithMonitor<T>(this ITypeConfiguration<T> @t
/// <seealso href="https://github.com/ExtendedXmlSerializer/home/issues/451" />
public static ITypeConfiguration<T> WithInterceptor<T>(this ITypeConfiguration<T> @this,
ISerializationInterceptor<T> interceptor)
=> @this.WithInterceptor(new SerializationInterceptor<T>(interceptor));

/// <summary>
/// Applies a generalized interceptor for type configuration. An interceptor participates in the serialization pipeline by being
/// introduced during key serialization and deserialization events.
/// </summary>
/// <param name="this">The type to intercept.</param>
/// <param name="interceptor">The interceptor to apply to a type.</param>
/// <typeparam name="T">The type argument of the type configuration being configured.</typeparam>
/// <returns>The configured type configuration.</returns>
/// <seealso href="https://github.com/ExtendedXmlSerializer/home/issues/451" />
public static ITypeConfiguration<T> WithInterceptor<T>(this ITypeConfiguration<T> @this,
ISerializationInterceptor interceptor)
=> @this.Root.With<SerializationInterceptionExtension>()
.Apply(Support<T>.Metadata, new SerializationInterceptor<T>(interceptor))
.Apply(Support<T>.Metadata, interceptor)
.Return(@this);

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using ExtendedXmlSerializer.ContentModel.Format;
using System;

namespace ExtendedXmlSerializer.ExtensionModel.Instances
{
/// <summary>
/// A generalized serialization interceptor base class for convenience.
/// </summary>
public abstract class SerializationActivator : ISerializationInterceptor
{
/// <inheritdoc />
public virtual object Serializing(IFormatWriter writer, object instance) => instance;

/// <inheritdoc />
public abstract object Activating(Type instanceType);

/// <inheritdoc />
public virtual object Deserialized(IFormatReader reader, object instance) => instance;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using ExtendedXmlSerializer.ContentModel.Format;
using ExtendedXmlSerializer.Core;
using ExtendedXmlSerializer.Core.Sources;
using ExtendedXmlSerializer.Core.Specifications;
using ExtendedXmlSerializer.ReflectionModel;
using JetBrains.Annotations;
using System;
Expand All @@ -21,15 +22,26 @@ public SerializationInterceptionExtension() : this(new TypedTable<ISerialization
public SerializationInterceptionExtension(ITypedTable<ISerializationInterceptor> registrations)
=> _registrations = registrations;

public IServiceRepository Get(IServiceRepository parameter) => parameter.Decorate<IActivators>(Register)
.Decorate<IContents>(Register);
public IServiceRepository Get(IServiceRepository parameter)
=> parameter.Decorate<IActivatingTypeSpecification>(Register)
.Decorate<IActivators>(Register)
.Decorate<IContents>(Register);

IContents Register(IServiceProvider _, IContents previous) => new Contents(_registrations, previous);

IActivatingTypeSpecification Register(IServiceProvider _, IActivatingTypeSpecification previous)
=> new IsActivatingType(_registrations, previous);

IActivators Register(IServiceProvider _, IActivators previous) => new Activators(_registrations, previous);

void ICommand<IServices>.Execute(IServices parameter) {}

sealed class IsActivatingType : AnySpecification<TypeInfo>, IActivatingTypeSpecification
{
public IsActivatingType(ISpecification<TypeInfo> specification, IActivatingTypeSpecification previous)
: base(specification, previous) {}
}

sealed class Contents : IContents
{
readonly ITypedTable<ISerializationInterceptor> _interceptors;
Expand Down Expand Up @@ -59,31 +71,33 @@ Serializer Create(TypeInfo parameter, ISerializer previous)
sealed class Activators : IActivators
{
readonly ITypedTable<ISerializationInterceptor> _table;
readonly IActivators _activators;
readonly IActivators _previous;

public Activators(ITypedTable<ISerializationInterceptor> table, IActivators activators)
public Activators(ITypedTable<ISerializationInterceptor> table, IActivators previous)
{
_table = table;
_activators = activators;
_table = table;
_previous = previous;
}

public IActivator Get(Type parameter)
=> new Activator(parameter, _activators.Get(parameter), _table.Get(parameter));
=> _table.IsSatisfiedBy(parameter)
? new Activator(parameter, _previous.Build(parameter), _table.Get(parameter))
: _previous.Get(parameter);

sealed class Activator : IActivator
{
readonly Type _instanceType;
readonly IActivator _activator;
readonly Func<IActivator> _activator;
readonly ISerializationInterceptor _interceptor;

public Activator(Type instanceType, IActivator activator, ISerializationInterceptor interceptor)
public Activator(Type instanceType, Func<IActivator> activator, ISerializationInterceptor interceptor)
{
_instanceType = instanceType;
_activator = activator;
_interceptor = interceptor;
}

public object Get() => _interceptor.Activating(_instanceType) ?? _activator.Get();
public object Get() => _interceptor.Activating(_instanceType) ?? _activator().Get();
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using ExtendedXmlSerializer.Configuration;
using ExtendedXmlSerializer.ExtensionModel.Instances;
using FluentAssertions;
using JetBrains.Annotations;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
using Xunit;

namespace ExtendedXmlSerializer.Tests.ReportedIssues
{
public sealed class Issue451Tests_Reported
{
[Fact]
public void TestInterceptor()
{
// language=XML
const string xml = @"<?xml version=""1.0"" encoding=""utf-8""?>
<Issue451Tests_Reported-Processor>
<Enabled>true</Enabled>
<Filters>
<Filter>
<Type>ISO</Type>
</Filter>
</Filters>
</Issue451Tests_Reported-Processor>";

var serializer = new ConfigurationContainer().EnableImplicitTyping(typeof(Processor))
.Type<Processor>()
.WithInterceptor(new Interceptor())
.Create();

var contentStream = new MemoryStream(Encoding.UTF8.GetBytes(xml));
using var reader = XmlReader.Create(contentStream);
var processor = (Processor)serializer.Deserialize(reader);
processor.Should().NotBeNull();
processor.Enabled.Should().BeTrue();
processor.Filters.Should().NotBeEmpty();
processor.Filters.Only().Type.Should().Be("ISO");
}

public class Interceptor : SerializationActivator
{
public override object Activating(Type instanceType)
{
// processor should be retrieved from IoC container, but created manually for simplicity of test
var processor = new Processor(new Service());
return processor;
}
}

public interface IService {}

class Service : IService {}

public class Processor
{
// ReSharper disable once NotAccessedField.Local
readonly IService _service;

public bool Enabled { get; set; }

public List<Filter> Filters { [UsedImplicitly] get; set; }

public Processor(IService service)
{
_service = service;

Filters = new List<Filter>();
}
}

public class Filter
{
public string Type { get; set; }
}
}
}

0 comments on commit a00f7af

Please sign in to comment.