Skip to content

Commit

Permalink
Changed serialization behavior for dynamic type resolving (now the se…
Browse files Browse the repository at this point in the history
…rializer uses type aliases instead of real type names)
  • Loading branch information
RolandKoenig committed Dec 12, 2020
1 parent eef50e9 commit f85e92a
Show file tree
Hide file tree
Showing 13 changed files with 115 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

namespace MessageCommunicator.TestGui.Data
{
[TypeAlias("ByteStreamHandlerSerialPortSettings")]
public class ByteStreamHandlerSerialPortSettings : IByteStreamHandlerAppSettings
{
private const string CATEGORY = "Serial Port";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

namespace MessageCommunicator.TestGui.Data
{
[TypeAlias("ByteStreamHandlerTcpSettings")]
public class ByteStreamHandlerTcpSettings : IByteStreamHandlerAppSettings
{
private const string CATEGORY = "Tcp";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

namespace MessageCommunicator.TestGui.Data
{
[TypeAlias("ByteStreamHandlerUdpSettings")]
public class ByteStreamHandlerUdpSettings : IByteStreamHandlerAppSettings
{
private const string CATEGORY = "Udp";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

namespace MessageCommunicator.TestGui.Data
{
[TypeAlias("MessageRecognizerByUnderlyingPackageSettings")]
public class MessageRecognizerByUnderlyingPackageSettings : IMessageRecognizerAppSettings
{
private const string CATEGORY = "ByUnderlyingPackage Recognizer";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

namespace MessageCommunicator.TestGui.Data
{
[TypeAlias("MessageRecognizerDefaultSettings")]
public class MessageRecognizerDefaultSettings : IMessageRecognizerAppSettings
{
private const string CATEGORY = "Default Recognizer";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

namespace MessageCommunicator.TestGui.Data
{
[TypeAlias("MessageRecognizerEndSymbolSettings")]
public class MessageRecognizerEndSymbolSettings : IMessageRecognizerAppSettings
{
private const string CATEGORY = "EndSymbol Recognizer";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

namespace MessageCommunicator.TestGui.Data
{
[TypeAlias("MessageRecognizerFixedLengthAndEndSymbolsSettings")]
public class MessageRecognizerFixedLengthAndEndSymbolsSettings : IMessageRecognizerAppSettings
{
private const string CATEGORY = "FixedLength and EndSymbols Recognizer";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

namespace MessageCommunicator.TestGui.Data
{
[TypeAlias("MessageRecognizerFixedLengthSettings")]
public class MessageRecognizerFixedLengthSettings : IMessageRecognizerAppSettings
{
private const string CATEGORY = "FixedLength Recognizer";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

namespace MessageCommunicator.TestGui.Data
{
[TypeAlias("MessageRecognizerStartAndEndSymbolSettings")]
public class MessageRecognizerStartAndEndSymbolSettings : IMessageRecognizerAppSettings
{
private const string CATEGORY = "Start- and EndSymbol Recognizer";
Expand Down
19 changes: 19 additions & 0 deletions MessageCommunicator.TestGui/_Util/_Misc.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MessageCommunicator.TestGui
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public class TypeAliasAttribute : Attribute
{
public string AliasName { get; }

public TypeAliasAttribute(string aliasName)
{
this.AliasName = aliasName;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

namespace MessageCommunicator.TestGui
{
public class DynamicMappingWithAliasSerializationBinder : DefaultSerializationBinder
{
private const string ASSEMBLY_ALIAS = "__alias";

private ResolveTypeByAliasDelegate _typeResolver;

public DynamicMappingWithAliasSerializationBinder(ResolveTypeByAliasDelegate typeResolver)
{
_typeResolver = typeResolver;
}

public override void BindToName(Type serializedType, out string assemblyName, out string typeName)
{
var aliasAttrib = serializedType.GetCustomAttribute<TypeAliasAttribute>();
if (aliasAttrib == null)
{
throw new JsonSerializationException(
$"Unable to serialize type {serializedType.FullName} because dynamic mapping is only supported for types with {nameof(TypeAliasAttribute)}!");
}

if (serializedType.IsGenericType)
{
throw new JsonSerializationException(
$"Unable to serialize type {serializedType.FullName} because dynamic mapping of generic types is not supported!");
}

assemblyName = ASSEMBLY_ALIAS;
typeName = aliasAttrib.AliasName;
}

public override Type BindToType(string? assemblyName, string typeName)
{
if (assemblyName != ASSEMBLY_ALIAS)
{
throw new JsonSerializationException($"Unable to load type {typeName} from assembly {assemblyName}: Dynamic resolving only available for alias names!");
}

var resolvedType = _typeResolver(typeName);
if (resolvedType == null)
{
throw new JsonSerializationException($"Unable to load type {typeName} from assembly {assemblyName}!");
}

return resolvedType;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Reflection.Metadata.Ecma335;
using System.Text;
using Newtonsoft.Json;

Expand All @@ -12,8 +14,27 @@ public static class SerializationHelper

static SerializationHelper()
{
Dictionary<string, Type> typesByAlias = new Dictionary<string, Type>(16);
foreach (var actType in Assembly.GetExecutingAssembly().GetTypes())
{
var aliasAttrib = actType.GetCustomAttribute<TypeAliasAttribute>();
if(aliasAttrib == null){ continue; }

typesByAlias[aliasAttrib.AliasName] = actType;
}


Serializer = new JsonSerializer();
Serializer.TypeNameHandling = TypeNameHandling.Auto;
Serializer.SerializationBinder = new DynamicMappingWithAliasSerializationBinder(
(aliasName) =>
{
if (typesByAlias.TryGetValue(aliasName, out var foundType))
{
return foundType;
}
return null;
});
}

public static T? DeserializeFromStream<T>(Stream inStream)
Expand Down
10 changes: 10 additions & 0 deletions MessageCommunicator.TestGui/_Util/_Serialization/_Misc.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MessageCommunicator.TestGui
{
public delegate Type? ResolveTypeByAliasDelegate(string aliasName);
}

0 comments on commit f85e92a

Please sign in to comment.