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 3c2881b90f..577d4723e7 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/ActorSelectionSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/ActorSelectionSpec.scala @@ -332,6 +332,14 @@ class ActorSelectionSpec extends AkkaSpec("akka.loglevel=DEBUG") with DefaultTim s"ActorSelection[Anchor(akka://ActorSelectionSpec/user/c2/c21#${c21.path.uid}), Path(/../*/hello)]") } + "have a stringly serializable path" in { + system.actorSelection(system / "c2").toSerializationFormat should be("akka://ActorSelectionSpec/user/c2") + system.actorSelection(system / "c2" / "c21").toSerializationFormat should be("akka://ActorSelectionSpec/user/c2/c21") + ActorSelection(c2, "/").toSerializationFormat should be("akka://ActorSelectionSpec/user/c2") + ActorSelection(c2, "../*/hello").toSerializationFormat should be("akka://ActorSelectionSpec/user/c2/../*/hello") + ActorSelection(c2, "/../*/hello").toSerializationFormat should be("akka://ActorSelectionSpec/user/c2/../*/hello") + } + "send ActorSelection targeted to missing actor to deadLetters" in { val p = TestProbe() system.eventStream.subscribe(p.ref, classOf[DeadLetter]) diff --git a/akka-actor/src/main/scala/akka/actor/ActorSelection.scala b/akka-actor/src/main/scala/akka/actor/ActorSelection.scala index 8dd4b4b84b..7d410344d4 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorSelection.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorSelection.scala @@ -99,6 +99,27 @@ abstract class ActorSelection extends Serializable { */ def pathString: String = path.mkString("/", "/", "") + /** + * String representation of the actor selection suitable for storage and recreation. + * The output is similar to the URI fragment returned by [[akka.actor.ActorPath.toSerializationFormat]]. + * @return URI fragment + */ + def toSerializationFormat: String = { + val anchorPath = anchor match { + case a: ActorRefWithCell ⇒ anchor.path.toStringWithAddress(a.provider.getDefaultAddress) + case _ ⇒ anchor.path.toString + } + + val builder = new java.lang.StringBuilder() + builder.append(anchorPath) + val lastChar = builder.charAt(builder.length - 1) + if (path.nonEmpty && lastChar != '/') + builder.append(path.mkString("/", "/", "")) + else if (path.nonEmpty) + builder.append(path.mkString("/")) + builder.toString + } + override def equals(obj: Any): Boolean = obj match { case s: ActorSelection ⇒ this.anchor == s.anchor && this.path == s.path case _ ⇒ false diff --git a/akka-remote/src/test/scala/akka/remote/RemotingSpec.scala b/akka-remote/src/test/scala/akka/remote/RemotingSpec.scala index 7e079c009f..6d3023b7b7 100644 --- a/akka-remote/src/test/scala/akka/remote/RemotingSpec.scala +++ b/akka-remote/src/test/scala/akka/remote/RemotingSpec.scala @@ -416,6 +416,10 @@ class RemotingSpec extends AkkaSpec(RemotingSpec.cfg) with ImplicitSender with D system.actorSelection(child.path / "*" / "grandgrandchild") ! Identify("idReq13") expectMsg(ActorIdentity("idReq13", Some(grandgrandchild))) + val sel1 = system.actorSelection("/user/looker2/child/grandchild/grandgrandchild") + system.actorSelection(sel1.toSerializationFormat) ! Identify("idReq18") + expectMsg(ActorIdentity("idReq18", Some(grandgrandchild))) + child ! Identify("idReq14") expectMsg(ActorIdentity("idReq14", Some(child))) watch(child)