Skip to content

Commit

Permalink
TypeExtensions.TypeQualifiedName like in Hyperion (#4071)
Browse files Browse the repository at this point in the history
* ported TypeExtensions.TypeQualifiedName resolution from Hyperion

* Unit test which proves that legacy and shortened types names are equivalent

* Check that shorter type manifest does not have version, culture and key attributes in it
  • Loading branch information
valdisz authored and Aaronontheweb committed Dec 15, 2019
1 parent d228f94 commit 51ed45f
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 10 deletions.
44 changes: 44 additions & 0 deletions src/core/Akka.Tests/Serialization/SerializationSpec.cs
Expand Up @@ -6,13 +6,20 @@
//-----------------------------------------------------------------------

using System;
using System.Collections.Concurrent;
using System.IO;
using System.Reflection;
using System.Text.RegularExpressions;
using Akka.Actor;
using Akka.Configuration;
using Akka.Dispatch.SysMsg;
using Akka.Routing;
using Akka.Serialization;
using Akka.TestKit;
using Akka.TestKit.TestActors;
using Akka.Util;
using Akka.Util.Reflection;
using FluentAssertions;
using Xunit;

namespace Akka.Tests.Serialization
Expand Down Expand Up @@ -552,6 +559,29 @@ public void Can_apply_a_config_based_serializer_by_the_binding()
dummy2.Config.GetString("test-key").ShouldBe("test value");
}


private static string LegacyTypeQualifiedName(Type type)
{
string coreAssemblyName = typeof(object).GetTypeInfo().Assembly.GetName().Name;
var assemblyName = type.GetTypeInfo().Assembly.GetName().Name;
var shortened = assemblyName.Equals(coreAssemblyName)
? type.GetTypeInfo().FullName
: $"{type.GetTypeInfo().FullName}, {assemblyName}";
return shortened;
}

[Fact]
public void Legacy_and_shortened_types_names_are_equivalent()
{
var targetType = typeof(ParentClass<OtherClassA, OtherClassB, OtherClassC>.ChildClass);

var legacyTypeManifest = LegacyTypeQualifiedName(targetType);
var newTypeManifest = targetType.TypeQualifiedName();

TypeCache.GetType(legacyTypeManifest).ShouldBeSame(TypeCache.GetType(newTypeManifest));
Type.GetType(legacyTypeManifest).ShouldBeSame(Type.GetType(newTypeManifest));
}

public SerializationSpec():base(GetConfig())
{
}
Expand Down Expand Up @@ -638,6 +668,20 @@ public override object FromBinary(byte[] bytes, Type type)
throw new NotImplementedException();
}
}

public sealed class OtherClassA { }

public sealed class OtherClassB { }

public sealed class OtherClassC { }

public sealed class ParentClass<T1, T2, T3>
{
public sealed class ChildClass
{
public string Value { get; set; }
}
}
}
}

38 changes: 38 additions & 0 deletions src/core/Akka.Tests/Util/TypeExtensionsTests.cs
Expand Up @@ -5,10 +5,12 @@
// </copyright>
//-----------------------------------------------------------------------

using System;
using System.Collections;
using System.Collections.Generic;
using Akka.TestKit;
using Akka.Util;
using FluentAssertions;
using Xunit;

namespace Akka.Tests.Util
Expand All @@ -33,6 +35,42 @@ public void Test_nongeneric_implements()
typeof(List<string>).Implements(typeof(IEnumerable<string>)).ShouldBe(true);
typeof(List<string>).Implements(typeof(IEnumerable<int>)).ShouldBe(false);
}

public static IEnumerable<object[]> TargetTypes
{
get
{
yield return new object[] { typeof(ParentClass<OtherClassA, OtherClassB, OtherClassC>.ChildClass) };
yield return new object[] { typeof(string) };
yield return new object[] { typeof(object) };
yield return new object[] { typeof(TypeExtensionsTests) };
}
}

[Theory]
[MemberData(nameof(TargetTypes))]
public void Type_qualified_name_includes_only_typename_and_assemblyname(Type targetType)
{
var manifest = targetType.TypeQualifiedName();

manifest.Should().NotContain("Version");
manifest.Should().NotContain("Culture");
manifest.Should().NotContain("PublicKeyToken");
}

public sealed class OtherClassA { }

public sealed class OtherClassB { }

public sealed class OtherClassC { }

public sealed class ParentClass<T1, T2, T3>
{
public sealed class ChildClass
{
public string Value { get; set; }
}
}
}
}

20 changes: 10 additions & 10 deletions src/core/Akka/Util/TypeExtensions.cs
Expand Up @@ -8,6 +8,7 @@
using System;
using System.Collections.Concurrent;
using System.Reflection;
using System.Text.RegularExpressions;
using Akka.Annotations;

namespace Akka.Util
Expand Down Expand Up @@ -42,7 +43,10 @@ public static bool Implements(this Type type, Type moreGeneralType)
}

private static readonly ConcurrentDictionary<Type, string> ShortenedTypeNames = new ConcurrentDictionary<Type, string>();
private static readonly string CoreAssemblyName = typeof(object).GetTypeInfo().Assembly.GetName().Name;

private static readonly Regex cleanAssemblyVersionRegex = new Regex(
@"(, Version=([\d\.]+))?(, Culture=[^,\] \t]+)?(, PublicKeyToken=(null|[\da-f]+))?",
RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);

/// <summary>
/// INTERNAL API
Expand All @@ -59,15 +63,11 @@ public static string TypeQualifiedName(this Type type)
{
return shortened;
}
else
{
var assemblyName = type.GetTypeInfo().Assembly.GetName().Name;
shortened = assemblyName.Equals(CoreAssemblyName)
? type.GetTypeInfo().FullName
: $"{type.GetTypeInfo().FullName}, {assemblyName}";
ShortenedTypeNames.TryAdd(type, shortened);
return shortened;
}

shortened = cleanAssemblyVersionRegex.Replace(type.AssemblyQualifiedName, string.Empty);
ShortenedTypeNames.TryAdd(type, shortened);

return shortened;
}
}
}
Expand Down

0 comments on commit 51ed45f

Please sign in to comment.