From 6288a7c82f4634a15005596e78ec9e8f188697ee Mon Sep 17 00:00:00 2001 From: Patrik Nordwall Date: Mon, 21 Mar 2016 11:00:59 +0100 Subject: [PATCH] avoid NPE in recoveryRunning, #19177 * recoveryRunning = true when called from constructor * better exceptions if some things are used to early in FSM and persistent FSM --- akka-actor/src/main/scala/akka/actor/FSM.scala | 13 ++++++++++--- .../main/scala/akka/persistence/Eventsourced.scala | 5 ++++- .../akka/persistence/fsm/PersistentFSMBase.scala | 12 +++++++++--- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/akka-actor/src/main/scala/akka/actor/FSM.scala b/akka-actor/src/main/scala/akka/actor/FSM.scala index ddab81883c..bb0c35145e 100644 --- a/akka-actor/src/main/scala/akka/actor/FSM.scala +++ b/akka-actor/src/main/scala/akka/actor/FSM.scala @@ -515,17 +515,24 @@ trait FSM[S, D] extends Actor with Listeners with ActorLogging { * * @see [[#startWith]] */ - final def initialize(): Unit = makeTransition(currentState) + final def initialize(): Unit = + if (currentState != null) makeTransition(currentState) + else throw new IllegalStateException("You must call `startWith` before calling `initialize`") /** * Return current state name (i.e. object of type S) */ - final def stateName: S = currentState.stateName + final def stateName: S = { + if (currentState != null) currentState.stateName + else throw new IllegalStateException("You must call `startWith` before using `stateName`") + } /** * Return current state data (i.e. object of type D) */ - final def stateData: D = currentState.stateData + final def stateData: D = + if (currentState != null) currentState.stateData + else throw new IllegalStateException("You must call `startWith` before using `stateData`") /** * Return next state data (available in onTransition handlers) diff --git a/akka-persistence/src/main/scala/akka/persistence/Eventsourced.scala b/akka-persistence/src/main/scala/akka/persistence/Eventsourced.scala index 1ef1ed4b54..72c0067e14 100644 --- a/akka-persistence/src/main/scala/akka/persistence/Eventsourced.scala +++ b/akka-persistence/src/main/scala/akka/persistence/Eventsourced.scala @@ -427,7 +427,10 @@ private[persistence] trait Eventsourced extends Snapshotter with PersistenceStas /** * Returns `true` if this persistent actor is currently recovering. */ - def recoveryRunning: Boolean = currentState.recoveryRunning + def recoveryRunning: Boolean = { + // currentState is null if this is called from constructor + if (currentState == null) true else currentState.recoveryRunning + } /** * Returns `true` if this persistent actor has successfully finished recovery. diff --git a/akka-persistence/src/main/scala/akka/persistence/fsm/PersistentFSMBase.scala b/akka-persistence/src/main/scala/akka/persistence/fsm/PersistentFSMBase.scala index b4a671d307..72734be987 100644 --- a/akka-persistence/src/main/scala/akka/persistence/fsm/PersistentFSMBase.scala +++ b/akka-persistence/src/main/scala/akka/persistence/fsm/PersistentFSMBase.scala @@ -309,17 +309,23 @@ trait PersistentFSMBase[S, D, E] extends Actor with Listeners with ActorLogging * * @see [[#startWith]] */ - final def initialize(): Unit = makeTransition(currentState) + final def initialize(): Unit = + if (currentState != null) makeTransition(currentState) + else throw new IllegalStateException("You must call `startWith` before calling `initialize`") /** * Return current state name (i.e. object of type S) */ - final def stateName: S = currentState.stateName + final def stateName: S = + if (currentState != null) currentState.stateName + else throw new IllegalStateException("You must call `startWith` before using `stateName`") /** * Return current state data (i.e. object of type D) */ - final def stateData: D = currentState.stateData + final def stateData: D = + if (currentState != null) currentState.stateData + else throw new IllegalStateException("You must call `startWith` before using `stateData`") /** * Return all defined state names