具有特征的案例类的scala / akka

时间:2016-07-22 13:42:58

标签: scala serialization akka traits case-class

我无法在特征中获取案例类来使用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$1.apply$mcV$sp(Serializer.scala:235)
    at akka.serialization.JavaSerializer$$anonfun$toBinary$1.apply(Serializer.scala:235)
    at akka.serialization.JavaSerializer$$anonfun$toBinary$1.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$1(Main.scala:29)

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

有没有人知道如何使这项工作或为什么失败?我正在使用Scala 2.11.8和Akka 2.4.8;我用sbt程序集构建和测试......

非常感谢任何见解!

1 个答案:

答案 0 :(得分:1)

删除注释时出现异常的原因是,在该代码中,您正在使序列化的类(PlusMinus等...)成为你正在混合它们的类Foo。因此,为了序列化这些类,封闭类也必须序列化。这就是为什么你必须首先从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方法中。这只是另一种解决问题的方法。