From 21be4afee563a158ce067b8595af349f7878e86e Mon Sep 17 00:00:00 2001 From: Gregorius Soedharmo Date: Thu, 29 Apr 2021 03:11:10 +0700 Subject: [PATCH 1/3] Change the base class of PrimitiveSerializers to SerializerWithStringManifest --- .../Serialization/PrimitiveSerializersSpec.cs | 6 +- .../Serialization/PrimitiveSerializers.cs | 58 ++++++++++++++----- 2 files changed, 47 insertions(+), 17 deletions(-) diff --git a/src/core/Akka.Remote.Tests/Serialization/PrimitiveSerializersSpec.cs b/src/core/Akka.Remote.Tests/Serialization/PrimitiveSerializersSpec.cs index aa8fe99a79d..e21b4d3ee05 100644 --- a/src/core/Akka.Remote.Tests/Serialization/PrimitiveSerializersSpec.cs +++ b/src/core/Akka.Remote.Tests/Serialization/PrimitiveSerializersSpec.cs @@ -8,6 +8,7 @@ using Akka.Configuration; using Akka.Remote.Configuration; using Akka.Remote.Serialization; +using Akka.Serialization; using Akka.TestKit; using FluentAssertions; using Xunit; @@ -57,10 +58,11 @@ public void Can_serialize_String(string value) private T AssertAndReturn(T message) { - var serializer = Sys.Serialization.FindSerializerFor(message); + var serializer = (SerializerWithStringManifest)Sys.Serialization.FindSerializerFor(message); serializer.Should().BeOfType(); var serializedBytes = serializer.ToBinary(message); - return (T)serializer.FromBinary(serializedBytes, typeof(T)); + var manifest = serializer.Manifest(message); + return (T)serializer.FromBinary(serializedBytes, manifest); } private void AssertEqual(T message) diff --git a/src/core/Akka.Remote/Serialization/PrimitiveSerializers.cs b/src/core/Akka.Remote/Serialization/PrimitiveSerializers.cs index 21c7a5665fb..127c6422d69 100644 --- a/src/core/Akka.Remote/Serialization/PrimitiveSerializers.cs +++ b/src/core/Akka.Remote/Serialization/PrimitiveSerializers.cs @@ -13,8 +13,12 @@ namespace Akka.Remote.Serialization { - public sealed class PrimitiveSerializers : Serializer + public sealed class PrimitiveSerializers : SerializerWithStringManifest { + internal const string StringManifest = "S"; + internal const string Int32Manifest = "I"; + internal const string Int64Manifest = "L"; + /// /// Initializes a new instance of the class. /// @@ -23,28 +27,52 @@ public PrimitiveSerializers(ExtendedActorSystem system) : base(system) { } - /// - public override bool IncludeManifest { get; } = true; - /// public override byte[] ToBinary(object obj) { - var str = obj as string; - if (str != null) return Encoding.UTF8.GetBytes(str); - if (obj is int) return BitConverter.GetBytes((int)obj); - if (obj is long) return BitConverter.GetBytes((long)obj); - - throw new ArgumentException($"Cannot serialize object of type [{obj.GetType().TypeQualifiedName()}]"); + switch (obj) + { + case string s: + return Encoding.UTF8.GetBytes(s); + case int i: + return BitConverter.GetBytes(i); + case long l: + return BitConverter.GetBytes(l); + default: + throw new ArgumentException($"Cannot serialize object of type [{obj.GetType()}]"); + } } /// - public override object FromBinary(byte[] bytes, Type type) + public override object FromBinary(byte[] bytes, string manifest) { - if (type == typeof(string)) return Encoding.UTF8.GetString(bytes); - if (type == typeof(int)) return BitConverter.ToInt32(bytes, 0); - if (type == typeof(long)) return BitConverter.ToInt64(bytes, 0); + switch (manifest) + { + case StringManifest: + return Encoding.UTF8.GetString(bytes); + case Int32Manifest: + return BitConverter.ToInt32(bytes, 0); + case Int64Manifest: + return BitConverter.ToInt64(bytes, 0); + default: + throw new ArgumentException($"Unimplemented deserialization of message with manifest [{manifest}] in [${GetType()}]"); + } + } - throw new ArgumentException($"Unimplemented deserialization of message with manifest [{type.TypeQualifiedName()}] in [${nameof(PrimitiveSerializers)}]"); + /// + public override string Manifest(object obj) + { + switch (obj) + { + case string _: + return StringManifest; + case int _: + return Int32Manifest; + case long _: + return Int64Manifest; + default: + throw new ArgumentException($"Cannot serialize object of type [{obj.GetType()}] in [{GetType()}]"); + } } } } From 51b54073a9ad6a3b166dc16b5444977c7585cdf4 Mon Sep 17 00:00:00 2001 From: Gregorius Soedharmo Date: Thu, 29 Apr 2021 03:25:35 +0700 Subject: [PATCH 2/3] Add backward compatibility to the wire format --- .../Serialization/PrimitiveSerializersSpec.cs | 12 ++++++++++++ .../Serialization/PrimitiveSerializers.cs | 16 ++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/core/Akka.Remote.Tests/Serialization/PrimitiveSerializersSpec.cs b/src/core/Akka.Remote.Tests/Serialization/PrimitiveSerializersSpec.cs index e21b4d3ee05..2cc9bbd4561 100644 --- a/src/core/Akka.Remote.Tests/Serialization/PrimitiveSerializersSpec.cs +++ b/src/core/Akka.Remote.Tests/Serialization/PrimitiveSerializersSpec.cs @@ -65,10 +65,22 @@ private T AssertAndReturn(T message) return (T)serializer.FromBinary(serializedBytes, manifest); } + private T AssertCrossPlatformAndReturn(T message) + { + var serializer = (SerializerWithStringManifest)Sys.Serialization.FindSerializerFor(message); + serializer.Should().BeOfType(); + var serializedBytes = serializer.ToBinary(message); + // GetType() will make sure that each namespace is compatible with the serializer + // as the test is run on each platform. + return (T)serializer.FromBinary(serializedBytes, message.GetType()); + } + private void AssertEqual(T message) { var deserialized = AssertAndReturn(message); Assert.Equal(message, deserialized); + deserialized = AssertCrossPlatformAndReturn(message); + Assert.Equal(message, deserialized); } } } diff --git a/src/core/Akka.Remote/Serialization/PrimitiveSerializers.cs b/src/core/Akka.Remote/Serialization/PrimitiveSerializers.cs index 127c6422d69..f8716c10f36 100644 --- a/src/core/Akka.Remote/Serialization/PrimitiveSerializers.cs +++ b/src/core/Akka.Remote/Serialization/PrimitiveSerializers.cs @@ -19,6 +19,16 @@ public sealed class PrimitiveSerializers : SerializerWithStringManifest internal const string Int32Manifest = "I"; internal const string Int64Manifest = "L"; + // .Net Core manifests + internal const string StringManifestNetCore = "System.String, System.Private.CoreLib"; + internal const string Int32ManifestNetCore = "System.Int32, System.Private.CoreLib"; + internal const string Int64ManifestNetCore = "System.Int64, System.Private.CoreLib"; + + // .Net Framework manifests + internal const string StringManifestNetFx = "System.String, mscorlib"; + internal const string Int32ManifestNetFx = "System.Int32, mscorlib"; + internal const string Int64ManifestNetFx = "System.Int64, mscorlib"; + /// /// Initializes a new instance of the class. /// @@ -49,10 +59,16 @@ public override object FromBinary(byte[] bytes, string manifest) switch (manifest) { case StringManifest: + case StringManifestNetCore: + case StringManifestNetFx: return Encoding.UTF8.GetString(bytes); case Int32Manifest: + case Int32ManifestNetCore: + case Int32ManifestNetFx: return BitConverter.ToInt32(bytes, 0); case Int64Manifest: + case Int64ManifestNetCore: + case Int64ManifestNetFx: return BitConverter.ToInt64(bytes, 0); default: throw new ArgumentException($"Unimplemented deserialization of message with manifest [{manifest}] in [${GetType()}]"); From 87998652067fedd964a6e01326ff91f1ca9b034c Mon Sep 17 00:00:00 2001 From: Gregorius Soedharmo Date: Thu, 29 Apr 2021 04:04:07 +0700 Subject: [PATCH 3/3] Update API Approver list --- .../Akka.API.Tests/CoreAPISpec.ApproveRemote.approved.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/Akka.API.Tests/CoreAPISpec.ApproveRemote.approved.txt b/src/core/Akka.API.Tests/CoreAPISpec.ApproveRemote.approved.txt index f3fc63faff7..a1348b470bc 100644 --- a/src/core/Akka.API.Tests/CoreAPISpec.ApproveRemote.approved.txt +++ b/src/core/Akka.API.Tests/CoreAPISpec.ApproveRemote.approved.txt @@ -434,11 +434,11 @@ namespace Akka.Remote.Serialization public override string Manifest(object obj) { } public override byte[] ToBinary(object obj) { } } - public sealed class PrimitiveSerializers : Akka.Serialization.Serializer + public sealed class PrimitiveSerializers : Akka.Serialization.SerializerWithStringManifest { public PrimitiveSerializers(Akka.Actor.ExtendedActorSystem system) { } - public override bool IncludeManifest { get; } - public override object FromBinary(byte[] bytes, System.Type type) { } + public override object FromBinary(byte[] bytes, string manifest) { } + public override string Manifest(object obj) { } public override byte[] ToBinary(object obj) { } } public class ProtobufSerializer : Akka.Serialization.Serializer