Skip to content

Commit

Permalink
Merge pull request #154 from akkadotnet/dev
Browse files Browse the repository at this point in the history
v0.9.12 Release
  • Loading branch information
Aaronontheweb authored Jan 20, 2020
2 parents 326f89f + f09ffdd commit 2cf4598
Show file tree
Hide file tree
Showing 11 changed files with 161 additions and 26 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

[![Join the chat at https://gitter.im/akkadotnet/Hyperion](https://badges.gitter.im/akkadotnet/Hyperion.svg)](https://gitter.im/akkadotnet/Hyperion?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

A high performance polymorphic serializer for the .NET framework, fork of the [Wire](https://github.com/rogeralsing/Wire) serializer.
A high performance polymorphic serializer for the .NET framework.

Current status: **BETA** (v0.9.7).
Current status: **BETA** (v0.9.12).

## License
Licensed under Apache 2.0, see [LICENSE](LICENSE) for the full text.
Expand Down
5 changes: 3 additions & 2 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
### 0.9.11 November 13 2019 ####
### 0.9.12 January 20 2020 ####

[Hyperion now targets .NET 4.5 again so it can be included inside Akka.NET v1.3.* releases](https://github.com/akkadotnet/Hyperion/pull/141).
* Added version tolerance during deserialization.
* Added `ArrayList` and non-generic `IEnumerable` support.
68 changes: 68 additions & 0 deletions src/Hyperion.Tests/Bugs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using FluentAssertions;
using Hyperion.Extensions;
using Xunit;

namespace Hyperion.Tests
Expand Down Expand Up @@ -85,6 +90,69 @@ public void CanSerializeMessageWithByte()
var res = serializer.Deserialize(stream);
}

/// <summary>
/// Fix for https://github.com/akkadotnet/Hyperion/issues/144
/// </summary>
[Fact]
public void CanFindTypeByManifest_WhenManifestContainsUnknownAssemblyVersion()
{
var serializer = new Serializer(new SerializerOptions(versionTolerance: true, preserveObjectReferences: true));
var type = typeof(ByteMessage);

MemoryStream GetStreamForManifest(string manifest)
{
var stream = new MemoryStream();
stream.WriteLengthEncodedByteArray(manifest.ToUtf8Bytes(), serializer.GetSerializerSession());
stream.Position = 0;
return stream;
}

// This is used in serialized manifest, should be something like 'Hyperion.Tests.Bugs+ByteMessage, Hyperion.Tests'
var shortName = type.GetShortAssemblyQualifiedName();
var shortNameStream = GetStreamForManifest(shortName);
// Something like 'Hyperion.Tests.Bugs+ByteMessage, Hyperion.Tests, Version=0.9.11.0, Culture=neutral, PublicKeyToken=null'
var fullName = type.AssemblyQualifiedName;
var fullNameStream = GetStreamForManifest(fullName);
// Set bad assembly version to make deserialization fail
var fullNameWithUnknownVersion = fullName.Remove(fullName.IndexOf(", Version=")) + ", Version=999999, Culture=neutral, PublicKeyToken=null";
var fullNameWithUnknownVersionStream = GetStreamForManifest(fullNameWithUnknownVersion);

this.Invoking(_ => TypeEx.GetTypeFromManifestFull(shortNameStream, serializer.GetDeserializerSession()))
.Should().NotThrow("When assembly short name is specified in manifest, should work");
this.Invoking(_ => TypeEx.GetTypeFromManifestFull(fullNameStream, serializer.GetDeserializerSession()))
.Should().NotThrow("When assembly fully qualified name specified and name is correct, should work even before fix");
// This one was initially failing
this.Invoking(_ => TypeEx.GetTypeFromManifestFull(fullNameWithUnknownVersionStream, serializer.GetDeserializerSession()))
.Should().NotThrow("When assembly fully qualified name specified and unknown/wrong, type should be detected anyway");
}

[Fact]
public void TypeEx_ToQualifiedAssemblyName_should_strip_version_correctly_for_mscorlib_substitution()
{
var version = TypeEx.ToQualifiedAssemblyName(
"System.Collections.Immutable.ImmutableDictionary`2[[System.String, mscorlib,%core%],[System.Int32, mscorlib,%core%]]," +
" System.Collections.Immutable, Version=1.2.1.0, PublicKeyToken=b03f5f7f11d50a3a",
ignoreAssemblyVersion: true);

var coreAssemblyName = typeof(TypeEx).GetField("CoreAssemblyName", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null);
if (coreAssemblyName == null)
throw new Exception($"CoreAssemblyName private static field does not exist in {nameof(TypeEx)} class anymore");

version.Should().Be("System.Collections.Immutable.ImmutableDictionary`2" +
$"[[System.String, mscorlib{coreAssemblyName}],[System.Int32, mscorlib{coreAssemblyName}]], System.Collections.Immutable");
}

[Fact]
public void TypeEx_ToQualifiedAssemblyName_should_strip_version_correctly_for_multiple_versions_specified()
{
var version = TypeEx.ToQualifiedAssemblyName(
"System.Collections.Immutable.ImmutableList`1[[Foo.Bar, Foo, Version=2019.12.10.1]], " +
"System.Collections.Immutable, Version=1.2.2.0, PublicKeyToken=b03f5f7f11d50a3a",
ignoreAssemblyVersion: true);

version.Should().Be("System.Collections.Immutable.ImmutableList`1[[Foo.Bar, Foo]], System.Collections.Immutable");
}

[Fact]
public void CanSerialieCustomType_bug()
{
Expand Down
24 changes: 24 additions & 0 deletions src/Hyperion.Tests/CollectionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,30 @@ public void CanSerializeList()
Assert.Equal(expected, actual);
}

[Fact]
public void CanSerializeArrayList()
{
var expected = new ArrayList()
{
new Something
{
BoolProp = true,
Else = new Else
{
Name = "Yoho"
},
Int32Prop = 999,
StringProp = "Yesbox!"
},
"a", 123
};

Serialize(expected);
Reset();
var actual = Deserialize<ArrayList>();
Assert.Equal(expected, actual);
}

[Fact]
public void CanSerializeLinkedList()
{
Expand Down
25 changes: 14 additions & 11 deletions src/Hyperion.Tests/CrossFrameworkSerializationTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Hyperion.Tests.Generator;
using Xunit;

Expand All @@ -15,22 +18,22 @@ public CrossFrameworkSerializationTests()
_originalObject = CrossFrameworkInitializer.Init();
}

[Fact]
public void CanSerializeCrossFramework()
public static IEnumerable<object[]> SerializationFiles()
{
const string defaultOutputPath = CrossFrameworkInitializer.DefaultOutputPath;
var testFiles = Directory.GetFiles(defaultOutputPath, "*.tf");
return testFiles.Select(x => new object[] { x });
}

Assert.NotEmpty(testFiles);

foreach (string testFile in testFiles)
[Theory]
[MemberData(nameof(SerializationFiles))]
public void CanSerializeCrossFramework(string fileName)
{
using (var fileStream = new FileStream(fileName, FileMode.Open))
{
using (var fileStream = new FileStream(testFile, FileMode.Open))
{
var crossFrameworkClass = _serializer.Deserialize<CrossFrameworkClass>(fileStream);
var crossFrameworkClass = _serializer.Deserialize<CrossFrameworkClass>(fileStream);

Assert.Equal(_originalObject, crossFrameworkClass);
}
Assert.Equal(_originalObject, crossFrameworkClass);
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/Hyperion.Tests/Hyperion.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="5.10.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(TestSdkVersion)" />
<PackageReference Include="System.Collections.Immutable" Version="1.6.0" />
<PackageReference Include="System.Collections.Immutable" Version="1.7.0" />
<PackageReference Include="xunit" Version="$(XunitVersion)" />
<PackageReference Include="xunit.runner.visualstudio" Version="$(XunitVersion)" />
</ItemGroup>
Expand Down
28 changes: 25 additions & 3 deletions src/Hyperion/Extensions/TypeEx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,26 @@ private static Type GetTypeFromManifestName(Stream stream, DeserializerSession s
shortName = shortName.Replace("mscorlib,%core%", "System.Private.CoreLib,%core%");
}
#endif
return LoadTypeByName(shortName);
});
}

var typename = ToQualifiedAssemblyName(shortName);
public static Type LoadTypeByName(string name)
{
try
{
// Try to load type name using strict version to avoid possible conflicts
// i.e. if there are different version available in GAC and locally
var typename = ToQualifiedAssemblyName(name, ignoreAssemblyVersion: false);
return Type.GetType(typename, true);
});
}
catch (FileLoadException)
{
var typename = ToQualifiedAssemblyName(name, ignoreAssemblyVersion: true);
return Type.GetType(typename, true);
}
}

public static Type GetTypeFromManifestFull(Stream stream, DeserializerSession session)
{
var type = GetTypeFromManifestName(stream, session);
Expand Down Expand Up @@ -228,9 +243,16 @@ public static string GetShortAssemblyQualifiedName(this Type self)
return name;
}

public static string ToQualifiedAssemblyName(string shortName)
public static string ToQualifiedAssemblyName(string shortName, bool ignoreAssemblyVersion)
{
// Strip out assembly version, if specified
if (ignoreAssemblyVersion)
{
shortName = cleanAssemblyVersionRegex.Replace(shortName, string.Empty);
}

var res = shortName.Replace(",%core%", CoreAssemblyName);

return res;
}

Expand Down
11 changes: 8 additions & 3 deletions src/Hyperion/Hyperion.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,25 @@
</PropertyGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.6' ">
<PackageReference Include="System.Reflection.TypeExtensions" Version="4.6.0" />
<PackageReference Include="Microsoft.CSharp" Version="4.6.0" />
<PackageReference Include="System.Reflection.TypeExtensions" Version="4.7.0" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<PackageReference Include="System.Runtime" Version="4.3.1" />
<PackageReference Include="Microsoft.CSharp" Version="4.6.0" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>

<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>Hyperion.Tests</_Parameter1>
</AssemblyAttribute>
</ItemGroup>

<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard1.6' ">
<DefineConstants>$(DefineConstants);NETSTANDARD16</DefineConstants>
Expand Down
11 changes: 11 additions & 0 deletions src/Hyperion/SerializerFactories/EnumerableSerializerFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,17 @@ private static Type GetEnumerableType(Type type)
private static ConstructorInfo GetEnumerableConstructor(Type type)
{
var enumerableType = GetEnumerableType(type);

/*
* In the event that we're serializing a non-generic IEnumerable such as an ArrayList,
* there aren't any generic parameters and the type returned will just be System.Object.
*
* The GetEnumerableType method extracts the generic argument from the IEnumerable<T> and uses that
* by default, however it will return null only for a non-generic implementation thus we use the
* null-coalescing operator to specify the return type as System.Object in order to serialize ArrayList
* types without errors.
*/
enumerableType = enumerableType ?? typeof(object);
var iEnumerableType = typeof(IEnumerable<>).MakeGenericType(enumerableType);
return enumerableType != null
? type.GetTypeInfo()
Expand Down
3 changes: 1 addition & 2 deletions src/Hyperion/ValueSerializers/TypeSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,7 @@ public override object ReadValue(Stream stream, DeserializerSession session)
if (shortname == null)
return null;

var name = TypeEx.ToQualifiedAssemblyName(shortname);
var type = Type.GetType(name,true);
var type = TypeEx.LoadTypeByName(shortname);

//add the deserialized type to lookup
if (session.Serializer.Options.PreserveObjectReferences)
Expand Down
5 changes: 3 additions & 2 deletions src/common.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
<PropertyGroup>
<Copyright>Copyright © 2016-2017 Akka.NET Team</Copyright>
<Authors>Akka.NET Team</Authors>
<VersionPrefix>0.9.11</VersionPrefix>
<PackageReleaseNotes>[Hyperion now targets .NET 4.5 again so it can be included inside Akka.NET v1.3.* releases](https://github.com/akkadotnet/Hyperion/pull/141).</PackageReleaseNotes>
<VersionPrefix>0.9.12</VersionPrefix>
<PackageReleaseNotes>Added version tolerance during deserialization.
Added `ArrayList` and non-generic `IEnumerable` support.</PackageReleaseNotes>
<PackageIconUrl>http://getakka.net/images/akkalogo.png</PackageIconUrl>
<PackageProjectUrl>https://github.com/akkadotnet/Hyperion</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/akkadotnet/Hyperion/blob/master/LICENSE</PackageLicenseUrl>
Expand Down

0 comments on commit 2cf4598

Please sign in to comment.