Skip to content

Commit

Permalink
FSharp API: fixed problem with jobject deserialization
Browse files Browse the repository at this point in the history
case when JObject contains invalid type

fix moved to Akka.Persistence.FSharp
  • Loading branch information
Horusiath committed Aug 4, 2015
1 parent e6ca2ac commit a0d5a28
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 2 deletions.
17 changes: 16 additions & 1 deletion src/core/Akka.FSharp/FsApi.fs
Original file line number Diff line number Diff line change
Expand Up @@ -240,14 +240,29 @@ 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<System.Type>|])
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<Actor<'Message> -> Cont<'Message, 'Returned>>) = FunActor(actor.Compile () ())
member __.Sender() : IActorRef = base.Sender
member __.Unhandled msg = base.Unhandled msg
override x.OnReceive msg =
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() =
Expand Down
62 changes: 61 additions & 1 deletion src/core/Akka.Persistence.FSharp/FsApi.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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<System.Type>|])

type PersistenceId = string

[<Interface>]
Expand Down Expand Up @@ -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 ()
Expand Down Expand Up @@ -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?
Expand Down Expand Up @@ -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 () =
Expand Down

0 comments on commit a0d5a28

Please sign in to comment.