存储案例对象时要使用哪个JSON库?

时间:2015-07-27 12:20:50

标签: json scala json4s akka-persistence

我需要将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持久性一起使用?

是否有一个库通过正确反射来处理案例对象的反序列化? - 或者有没有人有一个好的解决方法?

2 个答案:

答案 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和无形),它支持版本控制,在读取时自动迁移以及测试工具包,以确保所有旧版本的持久性事件仍然可读。