【问题标题】:scala/akka of case class with trait具有特征的案例类的scala / akka
【发布时间】:2016-11-26 10:50:02
【问题描述】:

我无法让特征中的案例类与 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
}

但如果我删除 cmets,则会引发异常:

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)

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

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

非常感谢您的任何见解!

【问题讨论】:

    标签: scala serialization akka traits case-class


    【解决方案1】:

    删除 cmets 时出现异常的原因是,在该代码中,您正在使正在序列化的类(PlusMinus 等...)成为类 @987654323 的一部分@ 因为你正在混合它们。因此,为了序列化这些类,封闭类也必须被序列化。这就是为什么你必须首先让FooSerializable 继承,这应该是第一个危险信号。现在,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 方法中。这只是解决问题的另一种方法。

    【讨论】:

    • 太棒了!这是一个很大的帮助和一个很好的描述......谢谢!
    猜你喜欢
    • 2012-10-22
    • 1970-01-01
    • 2018-06-02
    • 1970-01-01
    • 1970-01-01
    • 2020-11-19
    • 1970-01-01
    • 1970-01-01
    • 2011-04-07
    相关资源
    最近更新 更多