Serialization errors in PE tests

Hi all,

When writing PE tests, I like to be thorough about my assumptions and challenge that there are no issues that arise from my commands and responses.

My PE fixture looks like this:

private val system = ActorSystem("FooSpec", JsonSerializerRegistry.actorSystemSetupFor(FooSerializerRegistry))

def withDriver(testCode: PersistentEntityTestDriver[FooEntityCommand, api.FooEvent, FooState] => Any): Unit = {
  val driver = new PersistentEntityTestDriver(system, new FooEntity, "driver")

  try {
    testCode(driver)
  } finally {
    driver.getAllIssues shouldBe empty
  }
}

I find that when I respond with collections, I run into errors serializing helper classes of various common collections, seen below:

  • No serializer defined for class scala.collection.immutable.Map$EmptyMap$
  • class scala.collection.immutable.Set$EmptySet$ is not serializable
  • class scala.collection.immutable.Set$Set1 is not serializable

I’ve registered all parameter types in my JsonSerializerRegistry, but I still see this issue, failing my tests and my application.conf looks like this

akka.actor.serialization-bindings {
  "akka.Done" = akka-misc
}

Is this a bug in play-json, Lagom, neither, or both?


Lagom attempts to get the manifest class

scala> final case class Foo(s: String)
defined class Foo

scala> Set.empty[Foo].getClass.getName
res22: String = scala.collection.immutable.Set$EmptySet$

But a serializer for this hasn’t been registered. Should Lagom get the enclosing class instead, which would resolve to scala.collection.immutable.Set[Foo], which does indeed have a format?

Hi Elijah,

this is a rather common issue. The support for container types de/ser in Akka-based communications is discouraged and in Lagom we’re trying to stir people away from them too.

Communicating with a Persistent Entity (sending commands, rehydrating state or events, etc…) requires picking a deserializer from an erased type so supporting arbitrary container types is not a great choice. Specially if more specific types can be implemented in userland code.

PS: In a Service API, where the Service.Descriptor specifies the types and both server and client have the detailed information the de/ser can be selected for the exact types and container types (Option[], Set[...], Either[],…) should be fine.

(edit: punctuation)

So if I understand correctly, the prescribed way is to wrap the raw container in a thin class? i.e.,

when a PE command is handled, it should have a ReplyType[GetFoosResponse] instead of ReplyType[Set[api.Foo]]?


Edit

Yes! In the entity code, respond to the service with a thinly wrapped class and it works!

1 Like