我需要将akka事件序列化为json。基于 " What JSON library to use in Scala?"我尝试了几个库。由于我的序列化程序不应该知道所有具体事件,因此应该使用反射来序列化由case类和case对象组成的事件。 json4s似乎最符合我的要求。
class Json4sEventAdapter(system: ExtendedActorSystem) extends EventAdapter {
implicit val formats = Serialization.formats(FullTypeHints(List(classOf[Evt])))
override def toJournal(event: Any): Any = event match {
case e: AnyRef =>
write(e).getBytes(Charsets.UTF_8)}
override def fromJournal(event: Any, manifest: String): EventSeq = event match {
case e: Array[Byte] => {
EventSeq.single(read[Evt](new String(e.map(_.toChar))))}}
使用json4s的问题是,无论使用哪种实现Deserialization of objects produces different instances。 由于我们大量使用案例对象的模式匹配,这会破坏我们现有的所有代码。
所以我的问题是:在存储案例对象时,哪个JSON库可以与scala和akka持久性一起使用?
是否有一个库通过正确反射来处理案例对象的反序列化? - 或者有没有人有一个好的解决方法?
答案 0 :(得分:0)
我无法评论Json4s,因为我从未使用它,但我确实知道这在play-json中不是问题。你可以这样做:
import play.api.libs.json._
sealed trait MyEventBase
case object MyEvent extends MyEventBase
implicit val myEventBaseFormat: Format[MyEventBase] = Format(Reads.StringReads.collect(ValidationError("must be the string `MyEvent`") {
case "MyEvent" => MyEvent
}, Writes.pure("MyEvent"))
在这种情况下,序列化是一个简单的字符串,所以我捎带内置的StringReads
断言该项应该可以反序列化为一个字符串,然后使用collect
来缩小到特定的字符串。但基本的想法是,您在Reads
实例中提供了反序列化所需的特定值。在这里,它是单身case object
。因此,无论何时反序列化导致MyEventBase
的{{1}},您肯定会得到同样的实例。
在现实世界中,MyEvent
可能还有其他子类型,因此您构建MyEventBase
实例以创建某种形式的序列化类型标记,以便Writes
实例可以关闭反序列化为正确的子类型。比如,您可以序列化为JSON对象而不是裸字符串,并且该对象将具有标识子类型的Reads
字段。或者只使用Play JSON Extensions之类的内容自动为type
合成Format
合理的sealed trait
。
答案 1 :(得分:0)
我强烈建议您查看Stamina。它已被实现以解决您将遇到的akka-persistence中常见的大多数问题。
它提供了一个json序列化器(基于spray-json和无形),它支持版本控制,在读取时自动迁移以及测试工具包,以确保所有旧版本的持久性事件仍然可读。