Avoid infinite recursion in AbstractFSM with Java on Scala 2.12 #12887

This commit is contained in:
Johan Andrén 2017-05-22 15:41:19 +02:00 committed by GitHub
parent f528e67422
commit f2adb0a3fd
2 changed files with 65 additions and 6 deletions

View file

@ -0,0 +1,59 @@
/**
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
*/
package akka.actor;
import akka.testkit.AkkaJUnitActorSystemResource;
import akka.testkit.AkkaSpec;
import akka.testkit.TestProbe;
import akka.testkit.javadsl.TestKit;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.scalatest.junit.JUnitSuite;
public class AbstractFSMActorTest extends JUnitSuite {
public static class MyFSM extends AbstractFSM<String, String> {
private final ActorRef probe;
MyFSM(ActorRef probe) {
this.probe = probe;
onTransition(this::logTransition);
startWith("start", "data");
when("start", matchEventEquals("next", (newState, data) ->
goTo(newState)
));
when("next", AbstractFSM.NullFunction());
initialize();
}
private void logTransition(final String s1, final String s2) {
probe.tell(String.format("Transitioning from %1$s to %2$s.", s1, s2), getSelf());
}
}
@ClassRule
public static AkkaJUnitActorSystemResource actorSystemResource = new AkkaJUnitActorSystemResource("AbstractFSMActorTest",
AkkaSpec.testConf());
private final ActorSystem system = actorSystemResource.getSystem();
@Test
public void canCreateFSM() {
// Coverage for #22887 (failed with Scala 2.12 before fix)
TestProbe probe = new TestProbe(system);
ActorRef ref = system.actorOf(Props.create(MyFSM.class, probe.ref()));
probe.expectMsg("Transitioning from start to start.");
ref.tell("next", ActorRef.noSender());
probe.expectMsg("Transitioning from start to next.");
}
}

View file

@ -96,7 +96,7 @@ abstract class AbstractFSM[S, D] extends FSM[S, D] {
stateName: S,
stateTimeout: FiniteDuration,
stateFunctionBuilder: FSMStateFunctionBuilder[S, D]): Unit =
when(stateName, stateTimeout)(stateFunctionBuilder.build())
super.when(stateName, stateTimeout)(stateFunctionBuilder.build())
/**
* Set initial state. Call this method from the constructor before the [[#initialize]] method.
@ -119,7 +119,7 @@ abstract class AbstractFSM[S, D] extends FSM[S, D] {
* @param timeout state timeout for the initial state, overriding the default timeout for that state
*/
final def startWith(stateName: S, stateData: D, timeout: FiniteDuration): Unit =
startWith(stateName, stateData, Option(timeout))
super.startWith(stateName, stateData, Option(timeout))
/**
* Add a handler which is called upon each state transition, i.e. not when
@ -129,7 +129,7 @@ abstract class AbstractFSM[S, D] extends FSM[S, D] {
* called, not only the first one matching.</b>
*/
final def onTransition(transitionHandlerBuilder: FSMTransitionHandlerBuilder[S]): Unit =
onTransition(transitionHandlerBuilder.build().asInstanceOf[TransitionHandler])
super.onTransition(transitionHandlerBuilder.build().asInstanceOf[TransitionHandler])
/**
* Add a handler which is called upon each state transition, i.e. not when
@ -139,7 +139,7 @@ abstract class AbstractFSM[S, D] extends FSM[S, D] {
* called, not only the first one matching.</b>
*/
final def onTransition(transitionHandler: UnitApply2[S, S]): Unit =
onTransition(transitionHandler(_: S, _: S))
super.onTransition(transitionHandler(_: S, _: S))
/**
* Set handler which is called upon reception of unhandled messages. Calling
@ -148,14 +148,14 @@ abstract class AbstractFSM[S, D] extends FSM[S, D] {
* The current state may be queried using ``stateName``.
*/
final def whenUnhandled(stateFunctionBuilder: FSMStateFunctionBuilder[S, D]): Unit =
whenUnhandled(stateFunctionBuilder.build())
super.whenUnhandled(stateFunctionBuilder.build())
/**
* Set handler which is called upon termination of this FSM actor. Calling
* this method again will overwrite the previous contents.
*/
final def onTermination(stopBuilder: FSMStopBuilder[S, D]): Unit =
onTermination(stopBuilder.build().asInstanceOf[PartialFunction[StopEvent, Unit]])
super.onTermination(stopBuilder.build().asInstanceOf[PartialFunction[StopEvent, Unit]])
/**
* Create an [[akka.japi.pf.FSMStateFunctionBuilder]] with the first case statement set.