diff --git a/akka-actor/src/main/scala/akka/japi/JavaAPI.scala b/akka-actor/src/main/scala/akka/japi/JavaAPI.scala index 5ab556d82c..642600f2bd 100644 --- a/akka-actor/src/main/scala/akka/japi/JavaAPI.scala +++ b/akka-actor/src/main/scala/akka/japi/JavaAPI.scala @@ -5,10 +5,10 @@ package akka.japi import language.implicitConversions - import scala.Some import scala.reflect.ClassTag import scala.util.control.NoStackTrace +import scala.runtime.AbstractPartialFunction /** * A Function interface. Used to create first-class-functions is Java. @@ -53,7 +53,7 @@ trait Creator[T] { def create(): T } -object PurePartialFunction { +object JavaPartialFunction { sealed abstract class NoMatchException extends RuntimeException with NoStackTrace case object NoMatch extends NoMatchException final def noMatch(): RuntimeException = NoMatch @@ -71,7 +71,7 @@ object PurePartialFunction { * that expensive). * * {{{ - * new PurePartialFunction() { + * new JavaPartialFunction() { * public String apply(Object in, boolean isCheck) { * if (in instanceof TheThing) { * if (isCheck) return null; // to spare the expensive or side-effecting code @@ -95,33 +95,15 @@ object PurePartialFunction { * does not throw `noMatch()` it will continue with calling * `PurePartialFunction.apply(x, false)`. */ -abstract class PurePartialFunction[A, B] extends scala.runtime.AbstractFunction1[A, B] with PartialFunction[A, B] { - import PurePartialFunction._ +abstract class JavaPartialFunction[A, B] extends AbstractPartialFunction[A, B] { + import JavaPartialFunction._ @throws(classOf[Exception]) def apply(x: A, isCheck: Boolean): B final def isDefinedAt(x: A): Boolean = try { apply(x, true); true } catch { case NoMatch ⇒ false } - final def apply(x: A): B = try apply(x, false) catch { case NoMatch ⇒ throw new MatchError(x) } -} - -/** - * This is a specialized variant of PartialFunction which is only - * applicable if you know that `isDefinedAt(x)` is always called before - * `apply(x)`—with the same `x` of course. - * - * `match(x)` will be called for `isDefinedAt(x)` only, and its semantics - * are the same as for [[akka.japi.PurePartialFunction]] (apart from the - * missing because unneeded boolean argument). - */ -abstract class CachingPartialFunction[A, B <: AnyRef] extends scala.runtime.AbstractFunction1[A, B] with PartialFunction[A, B] { - import PurePartialFunction._ - - def `match`(x: A): B - - var cache: B = _ - final def isDefinedAt(x: A): Boolean = try { cache = `match`(x); true } catch { case NoMatch ⇒ cache = null.asInstanceOf[B]; false } - final def apply(x: A): B = cache + final override def apply(x: A): B = try apply(x, false) catch { case NoMatch ⇒ throw new MatchError(x) } + final override def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 ⇒ B1): B1 = try apply(x, false) catch { case NoMatch ⇒ default(x) } } /** diff --git a/akka-testkit/src/main/java/akka/testkit/JavaTestKit.java b/akka-testkit/src/main/java/akka/testkit/JavaTestKit.java index fda0eaa538..e8ce90a9ed 100644 --- a/akka-testkit/src/main/java/akka/testkit/JavaTestKit.java +++ b/akka-testkit/src/main/java/akka/testkit/JavaTestKit.java @@ -8,8 +8,7 @@ import akka.actor.ActorRef; import akka.actor.ActorSystem; import akka.event.Logging; import akka.event.Logging.LogEvent; -import akka.japi.PurePartialFunction; -import akka.japi.CachingPartialFunction; +import akka.japi.JavaPartialFunction; import akka.japi.Util; import scala.concurrent.util.Duration; @@ -79,7 +78,7 @@ public class JavaTestKit { abstract protected boolean ignore(Object msg); public IgnoreMsg() { - p.ignoreMsg(new PurePartialFunction() { + p.ignoreMsg(new JavaPartialFunction() { public Boolean apply(Object in, boolean isCheck) { return ignore(in); } @@ -148,7 +147,7 @@ public class JavaTestKit { final Object received = p.receiveOne(max); try { result = match(received); - } catch (PurePartialFunction.NoMatchException ex) { + } catch (JavaPartialFunction.NoMatchException ex) { throw new AssertionError("while expecting '" + hint + "' received unexpected: " + received); } @@ -157,7 +156,7 @@ public class JavaTestKit { abstract protected T match(Object msg); protected RuntimeException noMatch() { - throw PurePartialFunction.noMatch(); + throw JavaPartialFunction.noMatch(); } public T get() { @@ -218,7 +217,7 @@ public class JavaTestKit { } public abstract class ReceiveWhile { - abstract protected T match(Object msg); + abstract protected T match(Object msg) throws Exception; private Object results; @@ -238,14 +237,14 @@ public class JavaTestKit { public ReceiveWhile(Class clazz, Duration max, Duration idle, int messages) { results = p.receiveWhile(max, idle, messages, new CachingPartialFunction() { - public T match(Object msg) { - return ReceiveWhile.this.match(msg); + public T match(Object msg) throws Exception { + return ReceiveWhile.this.match(msg); } }).toArray(Util.classTag(clazz)); } protected RuntimeException noMatch() { - throw PurePartialFunction.noMatch(); + throw JavaPartialFunction.noMatch(); } @SuppressWarnings("unchecked") diff --git a/akka-testkit/src/main/scala/akka/testkit/TestKit.scala b/akka-testkit/src/main/scala/akka/testkit/TestKit.scala index cbdeb34a0d..19f63c1567 100644 --- a/akka-testkit/src/main/scala/akka/testkit/TestKit.scala +++ b/akka-testkit/src/main/scala/akka/testkit/TestKit.scala @@ -15,7 +15,6 @@ import scala.annotation.tailrec import akka.util.{ Timeout, BoxedType } import scala.annotation.varargs import scala.reflect.ClassTag -import akka.japi.PurePartialFunction object TestActor { type Ignore = Option[PartialFunction[AnyRef, Boolean]] @@ -48,6 +47,8 @@ object TestActor { override def msg: AnyRef = throw new IllegalActorStateException("last receive did not dequeue a message") override def sender: ActorRef = throw new IllegalActorStateException("last receive did not dequeue a message") } + + val FALSE = (x: Any) ⇒ false } class TestActor(queue: BlockingDeque[TestActor.Message]) extends Actor { @@ -67,7 +68,7 @@ class TestActor(queue: BlockingDeque[TestActor.Message]) extends Actor { case KeepRunning ⇒ autopilot case other ⇒ other } - val observe = ignore map (ignoreFunc ⇒ if (ignoreFunc isDefinedAt x) !ignoreFunc(x) else true) getOrElse true + val observe = ignore map (ignoreFunc ⇒ !ignoreFunc.applyOrElse(x, FALSE)) getOrElse true if (observe) queue.offerLast(RealMessage(x, sender)) } @@ -713,3 +714,28 @@ trait ImplicitSender { this: TestKit ⇒ trait DefaultTimeout { this: TestKit ⇒ implicit val timeout: Timeout = testKitSettings.DefaultTimeout } + +/** + * INTERNAL API + * + * This is a specialized variant of PartialFunction which is only + * applicable if you know that `isDefinedAt(x)` is always called before + * `apply(x)`—with the same `x` of course. + * + * `match(x)` will be called for `isDefinedAt(x)` only, and its semantics + * are the same as for [[akka.japi.PurePartialFunction]] (apart from the + * missing because unneeded boolean argument). + * + * This class is used internal to JavaTestKit and should not be extended + * by client code directly. + */ +private[testkit] abstract class CachingPartialFunction[A, B <: AnyRef] extends scala.runtime.AbstractPartialFunction[A, B] { + import akka.japi.JavaPartialFunction._ + + @throws(classOf[Exception]) + def `match`(x: A): B + + var cache: B = _ + final def isDefinedAt(x: A): Boolean = try { cache = `match`(x); true } catch { case NoMatch ⇒ cache = null.asInstanceOf[B]; false } + final override def apply(x: A): B = cache +}