diff --git a/akka-actor-tests/src/test/scala/akka/actor/ActorSelectionSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/ActorSelectionSpec.scala index 87c9f9057f..6ed49fe0b8 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/ActorSelectionSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/ActorSelectionSpec.scala @@ -18,6 +18,7 @@ object ActorSelectionSpec { case class SelectString(path: String) extends Query case class SelectPath(path: ActorPath) extends Query case class GetSender(to: ActorRef) extends Query + case class Forward(path: String, msg: Any) extends Query val p = Props[Node] @@ -27,6 +28,8 @@ object ActorSelectionSpec { case SelectString(path) ⇒ sender ! context.actorSelection(path) case SelectPath(path) ⇒ sender ! context.actorSelection(path) case GetSender(ref) ⇒ ref ! sender + case Forward(path, msg) ⇒ context.actorSelection(path).forward(msg) + case msg ⇒ sender ! msg } } @@ -328,6 +331,12 @@ class ActorSelectionSpec extends AkkaSpec("akka.loglevel=DEBUG") with DefaultTim ActorSelection(c21, "../*/hello").toString must be(s"ActorSelection[Actor[akka://ActorSelectionSpec/user/c2/c21#${c21.path.uid}]/../*/hello]") } + "forward to selection" in { + c2.tell(Forward("c21", "hello"), testActor) + expectMsg("hello") + lastSender must be(c21) + } + } } diff --git a/akka-actor/src/main/scala/akka/actor/ActorRef.scala b/akka-actor/src/main/scala/akka/actor/ActorRef.scala index 2ddbcd3d7f..d8ae428c10 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorRef.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorRef.scala @@ -115,20 +115,17 @@ abstract class ActorRef extends java.lang.Comparable[ActorRef] with Serializable } /** - * Java API: Sends the specified message to the sender, i.e. fire-and-forget - * semantics, including the sender reference if possible (pass `null` if - * there is nobody to reply to). + * Sends the specified message to the sender, i.e. fire-and-forget + * semantics, including the sender reference if possible. * - *
- * actor.tell(message, getSelf()); - *+ * Pass [[ActorRef#noSender]] or `null` as sender if there is nobody to reply to */ final def tell(msg: Any, sender: ActorRef): Unit = this.!(msg)(sender) /** * Forwards the message and passes the original sender actor as the sender. * - * Works with '!' and '?'/'ask'. + * Works, no matter whether originally sent with tell/'!' or ask/'?'. */ def forward(message: Any)(implicit context: ActorContext) = tell(message, context.sender) diff --git a/akka-actor/src/main/scala/akka/actor/ActorSelection.scala b/akka-actor/src/main/scala/akka/actor/ActorSelection.scala index 7b2b542dd8..0455aeb4ea 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorSelection.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorSelection.scala @@ -33,10 +33,23 @@ abstract class ActorSelection extends Serializable { @deprecated("use the two-arg variant (typically getSelf() as second arg)", "2.2") def tell(msg: Any): Unit = tell(msg, Actor.noSender) + /** + * Sends the specified message to the sender, i.e. fire-and-forget + * semantics, including the sender reference if possible. + * + * Pass [[ActorRef#noSender]] or `null` as sender if there is nobody to reply to + */ def tell(msg: Any, sender: ActorRef): Unit = ActorSelection.deliverSelection(anchor.asInstanceOf[InternalActorRef], sender, ActorSelectionMessage(msg, path)) + /** + * Forwards the message and passes the original sender actor as the sender. + * + * Works, no matter whether originally sent with tell/'!' or ask/'?'. + */ + def forward(message: Any)(implicit context: ActorContext) = tell(message, context.sender) + /** * Resolve the [[ActorRef]] matching this selection. * The result is returned as a Future that is completed with the [[ActorRef]]