diff --git a/src/core/Akka.FSharp/FsApi.fs b/src/core/Akka.FSharp/FsApi.fs index fdc46b9569d..056af07ff5e 100644 --- a/src/core/Akka.FSharp/FsApi.fs +++ b/src/core/Akka.FSharp/FsApi.fs @@ -240,6 +240,20 @@ module Actors = member __.Unstash() = (this :> IWithUnboundedStash).Stash.Unstash() member __.UnstashAll() = (this :> IWithUnboundedStash).Stash.UnstashAll() } + // these three static guys are hacks around issue with unresolved + // final type from Newtonsoft.Json serialization of some types + static let jobjectType = Type.GetType("Newtonsoft.Json.Linq.JObject, Newtonsoft.Json") + static let toObjectMethod = jobjectType.GetMethod("ToObject", [|typeof|]) + static let (|JObj|_|) o = + let t = typeof<'Message> + if o <> null && o.GetType().Equals jobjectType + then + try + Some (toObjectMethod.Invoke(o, [|t|]) :?> 'Message) + with + | _ -> None // type conversion failed (passed JSON is not of expected type) + else None + new(actor : Expr -> Cont<'Message, 'Returned>>) = FunActor(actor.Compile () ()) member __.Sender() : IActorRef = base.Sender member __.Unhandled msg = base.Unhandled msg @@ -247,7 +261,8 @@ module Actors = match state with | Func f -> match msg with - | :? 'Message as matched -> state <- f matched + | :? 'Message as m -> state <- f m + | JObj m -> state <- f m | _ -> x.Unhandled msg | Return _ -> x.PostStop() override x.PostStop() = diff --git a/src/core/Akka.Persistence.FSharp/FsApi.fs b/src/core/Akka.Persistence.FSharp/FsApi.fs index 082c194bb37..178a63f449e 100644 --- a/src/core/Akka.Persistence.FSharp/FsApi.fs +++ b/src/core/Akka.Persistence.FSharp/FsApi.fs @@ -12,6 +12,9 @@ open Akka.Actor open Akka.FSharp open Akka.Persistence +let private jobjectType = Type.GetType("Newtonsoft.Json.Linq.JObject, Newtonsoft.Json") +let private toObjectMethod = jobjectType.GetMethod("ToObject", [|typeof|]) + type PersistenceId = string [] @@ -142,16 +145,38 @@ type FunPersistentActor<'Command, 'Event, 'State>(aggregate: Aggregate<'Command, member __.SaveSnapshot state = this.SaveSnapshot(state) member __.DeleteSnapshot seqNr timestamp = this.DeleteSnapshot(seqNr, timestamp) member __.DeleteSnapshots criteria = this.DeleteSnapshots(criteria) } - + + static let (|JObjCommand|_|) o = + let t = typeof<'Command> + if o <> null && o.GetType().Equals jobjectType + then + try + Some (toObjectMethod.Invoke(o, [|t|]) :?> 'Message) + with + | _ -> None // type conversion failed (passed JSON is not of expected type) + else None + + static let (|JObjEvent|_|) o = + let t = typeof<'Event> + if o <> null && o.GetType().Equals jobjectType + then + try + Some (toObjectMethod.Invoke(o, [|t|]) :?> 'Message) + with + | _ -> None // type conversion failed (passed JSON is not of expected type) + else None + member __.Sender() : IActorRef = base.Sender member __.Unhandled msg = base.Unhandled msg override x.OnCommand (msg: obj) = match msg with | :? 'Command as cmd -> aggregate.exec mailbox state cmd + | JObjCommand cmd -> aggregate.exec mailbox state cmd | _ -> () // ignore? override x.OnRecover (msg: obj) = match msg with | :? 'Event as e -> state <- aggregate.apply mailbox state e + | JObjEvent e -> state <- aggregate.apply mailbox state e | _ -> () // ignore? override x.PostStop () = base.PostStop () @@ -259,11 +284,24 @@ type FunPersistentView<'Event, 'State>(perspective: Perspective<'Event, 'State>, member __.DeleteSnapshot seqNr timestamp = this.DeleteSnapshot(seqNr, timestamp) member __.DeleteSnapshots criteria = this.DeleteSnapshots(criteria) } + static let (|JObjEvent|_|) o = + let t = typeof<'Event> + if o <> null && o.GetType().Equals jobjectType + then + try + Some (toObjectMethod.Invoke(o, [|t|]) :?> 'Message) + with + | _ -> None // type conversion failed (passed JSON is not of expected type) + else None + member __.Sender() : IActorRef = base.Sender member __.Unhandled msg = base.Unhandled msg override x.Receive (msg: obj): bool = match msg with | :? 'Event as e -> + state <- perspective.apply mailbox state e + true + | JObjEvent e -> state <- perspective.apply mailbox state e true | _ -> false // ignore? @@ -330,16 +368,38 @@ type Deliverer<'Command, 'Event, 'State>(aggregate: DeliveryAggregate<'Command, member __.SetDeliverySnapshot snap = this.SetDeliverySnapshot snap member __.UnconfirmedCount() = this.UnconfirmedCount } + static let (|JObjCommand|_|) o = + let t = typeof<'Command> + if o <> null && o.GetType().Equals jobjectType + then + try + Some (toObjectMethod.Invoke(o, [|t|]) :?> 'Message) + with + | _ -> None // type conversion failed (passed JSON is not of expected type) + else None + + static let (|JObjEvent|_|) o = + let t = typeof<'Event> + if o <> null && o.GetType().Equals jobjectType + then + try + Some (toObjectMethod.Invoke(o, [|t|]) :?> 'Message) + with + | _ -> None // type conversion failed (passed JSON is not of expected type) + else None + member __.Sender() : IActorRef = base.Sender member __.Unhandled msg = base.Unhandled msg override x.ReceiveCommand (msg: obj) = match msg with | :? 'Command as cmd -> aggregate.exec mailbox state cmd + | JObjCommand cmd -> aggregate.exec mailbox state cmd | _ -> () // ignore? true override x.ReceiveRecover (msg: obj) = match msg with | :? 'Event as e -> state <- aggregate.apply mailbox state e + | JObjEvent e -> state <- aggregate.apply mailbox state e | _ -> () // ignore? true override x.PostStop () =