Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added reproduction for DU serialization #5196

Merged

Conversation

Aaronontheweb
Copy link
Member

close #5194

| D of int

type RemoteSpecs(output:ITestOutputHelper) as this =
inherit AkkaSpec((remoteConfig 0), output)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A little convoluted, but this is how you can pass through the XUnit ITestOutputHelper and the AkkaSpec / TestKit base members into an F# test

spawne clientSys "a-1" <@ actorOf2 (fun mailbox msg ->
match msg with
| C("a-11", B(11, "a-12")) -> mailbox.Sender() <! msg
| _ -> mailbox.Unhandled msg) @>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a clear reproduction here - we receive a JObject instead of a DU here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated this to use Hyperion - even a basic Newtonsoft.Json serialization setup can't handle DUs

Copy link
Contributor

@Horusiath Horusiath Aug 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I remember correctly - but I might be wrong - the issue might be caused by the fact that you either didn't configured JSON.NET to include type name as part of the payload or to use it if it was included. Since at the deserialization time payload type is still unknown and JSON.NET will use JObject as representation of System.Object instance. Casting it to typed actor message afterwards is already too late and will fail.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, with type hints Newtonsoft.Json correctly deserializes DUs:

member this.VerifySerialization msg =
let serializer = this.Sys.Serialization.FindSerializerFor msg
let t = msg.GetType()
let bytes = this.Sys.Serialization.Serialize msg
let deserialized =
match serializer :> obj with
| :? SerializerWithStringManifest as str -> this.Sys.Serialization.Deserialize(bytes, serializer.Identifier, str.Manifest msg)
| _ -> this.Sys.Serialization.Deserialize(bytes, serializer.Identifier, t)
Assert.Equal(msg, deserialized)

We disabled exposing type hints during the advent of Akka.NET v1.3 because of mscorlib namespace issues introduced by the creation of .NET Core: https://twitter.com/Danthar/status/1426204694310014981 cc @Danthar

We could fix the issue by turning type hints on, but it would blow up anyone doing .NET Framework --> .NET Core interop with Newtonsoft.Json (population of people doing that is great than zero) - or we could make it configurable to turn that setting on or off.

Copy link
Contributor

@Horusiath Horusiath Aug 14, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can potentially handle that as special case inside of typed actor itself:

override x.OnReceive msg =
match state with
| Func f ->
match msg with
| :? 'Message as m -> state <- f m
| _ -> x.Unhandled msg
| Return _ -> x.PostStop()

Add another match case to check if obj is JObject and if so use its ToObject method.

Copy link
Member Author

@Aaronontheweb Aaronontheweb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Described my work on adding better F# DU testing support going forward - looks like Newtonsoft.Json really can't support DUs even with DiscriminatedUnionConverter

spawne clientSys "a-1" <@ actorOf2 (fun mailbox msg ->
match msg with
| C("a-11", B(11, "a-12")) -> mailbox.Sender() <! msg
| _ -> mailbox.Unhandled msg) @>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated this to use Hyperion - even a basic Newtonsoft.Json serialization setup can't handle DUs

[<MemberData(nameof(SerializationSpecs.FSharpTypes))>]
member _.``Must verify serialization of F#-specific types`` (t:obj) =
this.VerifySerialization t
// uncomment the section below when experimenting with IncludeManifest = true on the Newtonsoft.Json serializer
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we enable IncludeManifest = true in the NewtonsoftJsonSerializer all of these tests will pass, including the ones currently using Hyperion right now. However, I'm not sure how significant of a change that might be and I'm loathe to touch it given that it powers so many Akka.Persistence serialization schemes.

@@ -35,7 +35,7 @@ module Serialization =
override __.FromBinary(bytes, _) = deserializeFromBinary fsp bytes


let internal exprSerializationSupport (system: ActorSystem) =
let exprSerializationSupport (system: ActorSystem) =
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

made this public



[<Fact(Skip="JSON.NET really does not support even basic DU serialization")>]
member _.``JSON.NET must serialize DUs`` () =
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Smoking gun - JsonConvert can't deserialize a DU even with DiscriminatedUnionConverter and none of our other customizations to Newtonsoft.Json. Will need to file an issue over there.

@Aaronontheweb Aaronontheweb marked this pull request as ready for review August 13, 2021 01:58
Copy link
Contributor

@Arkatufus Arkatufus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Arkatufus Arkatufus merged commit d201452 into akkadotnet:dev Aug 13, 2021
@Aaronontheweb Aaronontheweb deleted the fsharp/fix-5194-DUSerialization branch August 13, 2021 16:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Akka.FSharp: need to re-enable discriminated union (DU) serialization tests
3 participants