diff --git a/akka-components/src/main/scala/ClusterComponent.scala b/akka-components/src/main/scala/ClusterComponent.scala index bc8606b..415e137 100644 --- a/akka-components/src/main/scala/ClusterComponent.scala +++ b/akka-components/src/main/scala/ClusterComponent.scala @@ -415,11 +415,17 @@ object ClusterComponent { trait JsonEntityId { _: ShardedT => + /** + * The placeholder that will replace any | in the produced String as this character is illegal due to Akka's entityId encoding. + * When overriding keep the new placeholder permanently or existing entities won't be resolved. + * */ + val barPlaceholder = "❘❘bar❘❘" + implicit val entityIdCirceCodec: Codec[EntityId] implicit val entityIdCodec: EntityIdCodec[EntityId] = EntityIdCodec[EntityId]( - _.asJson.noSpacesSortKeys, - _.pipe(parser.parse).flatMap(_.as[EntityId]).toTry + _.asJson.noSpacesSortKeys.replace("|", barPlaceholder), + _.replace(barPlaceholder, "|").pipe(parser.parse).flatMap(_.as[EntityId]).toTry ) } diff --git a/akka-components/src/test/scala/ClusterComponentSpec.scala b/akka-components/src/test/scala/ClusterComponentSpec.scala index db7b4a7..522e674 100644 --- a/akka-components/src/test/scala/ClusterComponentSpec.scala +++ b/akka-components/src/test/scala/ClusterComponentSpec.scala @@ -255,7 +255,42 @@ class ClusterComponentSpec extends ScalaTestWithActorTestKit(ConfigFactory.parse val component = new ComponentObject.Component ComponentObject.init(component).delayedInit() - component.entityRefFor(ComponentObject.EntityId("a", "b")) + val entityRef = component.entityRefFor(ComponentObject.EntityId("a", "b")) + entityRef.entityId shouldBe """{"id1":"a","id2":"b"}""" + + val entityRefWithPlaceholder = component.entityRefFor(ComponentObject.EntityId("a|b", "c|d")) + entityRefWithPlaceholder.entityId shouldBe """{"id1":"a❘❘bar❘❘b","id2":"c❘❘bar❘❘d"}""" + } + "custom json EntityId with custom placeholder" in { + object ComponentObject extends ClusterComponent.Sharded with ClusterComponent.SameSerializableCommand with ClusterComponent.Sharded.JsonEntityId { + override val barPlaceholder = "/" + + case class EntityId(id1: String, id2: String) + + override implicit val entityIdCirceCodec = deriveCodec + + case class Command() + + object Command { + implicit val codec: Codec[Command] = deriveCodec + } + + class Component extends BaseComponent { + override val behavior = _ => + Behaviors.receiveMessage { + case Command() => Behaviors.same + } + } + + override val name = randomName + + override val commandSerializer = CirceSerializer() + } + + val component = new ComponentObject.Component + ComponentObject.init(component).delayedInit() + val entityRefWithPlaceholder = component.entityRefFor(ComponentObject.EntityId("a|b", "c|d")) + entityRefWithPlaceholder.entityId shouldBe """{"id1":"a/b","id2":"c/d"}""" } "long EntityId" in { object ComponentObject extends ClusterComponent.Sharded with ClusterComponent.SameSerializableCommand with ClusterComponent.Sharded.LongEntityId {