scala/akka 个案例 class 具有特征

scala/akka of case class with trait

我无法在使用 Akka 序列化的特征中获取大小写 类。以下代码按预期工作:

import akka.actor.ActorSystem
import akka.serialization.SerializationExtension

/*trait TestProtocol {*/
  sealed abstract class Expr /* extends Serializable */
  final case class Literal(v: Double) extends Expr
  final case class Plus(a: Expr, b: Expr) extends Expr
  final case class Minus(a: Expr, b: Expr) extends Expr
  final case class Times(a: Expr, b: Expr) extends Expr
  final case class Divide(a: Expr, b: Expr) extends Expr
/*}*/

class Foo /* extends Serializable with TestProtocol */ {
  val system = ActorSystem("snitch")
  def sample = List(
    Plus(Literal(9),Literal(5)),
    Times(Plus(Literal(1),Literal(18)),Literal(2))
  )
  val serialization = SerializationExtension(system)
  val serializer = serialization.findSerializerFor(sample)
  val bytes = serializer.toBinary(sample)
  val back = serializer.fromBinary(bytes, manifest = None)
  println(s">>>>>>> pre-serialize: ${sample}")
  println(s">>>>>>>  deserialized: ${back}")
}

object Main extends App {
  val bar = new Foo
  bar.system.terminate
}

但是如果我删除评论,就会抛出异常:

Exception in thread "main" java.io.NotSerializableException: akka.serialization.Serialization
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
    at scala.collection.immutable.List$SerializationProxy.writeObject(List.scala:468)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:988)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
    at akka.serialization.JavaSerializer$$anonfun$toBinary.apply$mcV$sp(Serializer.scala:235)
    at akka.serialization.JavaSerializer$$anonfun$toBinary.apply(Serializer.scala:235)
    at akka.serialization.JavaSerializer$$anonfun$toBinary.apply(Serializer.scala:235)
    at scala.util.DynamicVariable.withValue(DynamicVariable.scala:58)
    at akka.serialization.JavaSerializer.toBinary(Serializer.scala:235)
    at buggy.Foo.<init>(Main.scala:22)
    at buggy.Main$.delayedEndpoint$buggy$Main(Main.scala:29)

尝试反序列化字节字符串时。即使在我尝试使任何相关的 类 可序列化(如评论中所示)之后,我也会得到异常。

有谁知道如何进行这项工作或为什么会失败?我正在使用 Scala 2.11.8 和 Akka 2.4.8;我用 sbt assembly 构建和测试...

非常感谢任何见解!

删除注释时出现异常的原因是,在该代码中,您正在制作正在序列化的 classes(PlusMinus 等...) class Foo 的一部分,因为你正在混合它们。因此,为了序列化那些 classes,封闭的 class 也必须是也连载了这就是为什么您首先必须让 Foo 继承自 Serializable,这应该是第一个危险信号。现在,actor 系统和序列化扩展是 Foo 上的字段,因此序列化代码也需要序列化它们,这就是失败的来源。

您可以通过多种方式解决此问题。一种是将 TestProtocol 定义为 object,然后将其导入到 Foo 中,而不是将其作为 trait 混合。如果你打算混合它,那么你可以让你的代码看起来像这样:

object Main extends App {
  val bar = new Foo
  bar.run
}

trait TestProtocol {
  sealed abstract class Expr extends Serializable
  final case class Literal(v: Double) extends Expr
  final case class Plus(a: Expr, b: Expr) extends Expr
  final case class Minus(a: Expr, b: Expr) extends Expr
  final case class Times(a: Expr, b: Expr) extends Expr
  final case class Divide(a: Expr, b: Expr) extends Expr
}

class Foo extends Serializable with TestProtocol  {

  def run = {
    val system = ActorSystem("snitch")
    def sample = List(
      Plus(Literal(9),Literal(5)),
      Times(Plus(Literal(1),Literal(18)),Literal(2))
    )
    val serialization = SerializationExtension(system)
    val serializer = serialization.findSerializerFor(sample)
    val bytes = serializer.toBinary(sample)
    val back = serializer.fromBinary(bytes, manifest = None)
    println(s">>>>>>> pre-serialize: ${sample}")
    println(s">>>>>>>  deserialized: ${back}")
    system.terminate
  }
}

这里,Foo 中没有字段,因为我已经将 actor 系统等推入了 run 方法。这只是解决您的问题的另一种方法。