我正在尝试使用akka远程actor发送消息,其中case类是在其构造函数中获取参数的超类的子类 .
以下是重现问题的最小示例:
package com.tuvistavie.testremote
import akka.actor.{ Actor, ActorSystem, Props, ActorLogging }
import com.typesafe.config.ConfigFactory
abstract class Foo(val a: Int)
case class MessageFoo(override val a: Int) extends Foo(a)
object Sender {
def main(args: Array[String]) {
val system = ActorSystem("Sender", ConfigFactory.load.getConfig("sender"))
val actor = system.actorFor("akka://Receiver@127.0.0.1:2552/user/receiver")
actor ! MessageFoo(1)
}
}
object Receiver {
class ReceiverActor extends Actor with ActorLogging {
def receive = {
case m: MessageFoo => log.debug(m.toString)
}
}
def main(args: Array[String]) {
val system = ActorSystem("Receiver", ConfigFactory.load.getConfig("receiver"))
val actor = system.actorOf(Props[ReceiverActor], "receiver")
}
}
运行此代码时,我收到以下错误:
[ERROR] [06/26/2013 02:53:16.132] [Receiver-9]
[NettyRemoteTransport(akka://Receiver@127.0.0.1:2552)]
RemoteServerError@akka://Receiver@127.0.0.1:2552] Error[java.io.InvalidClassException: com.tuvistavie.testremote.MessageFoo; no valid constructor]
我认为这是因为消息无法反序列化(使用 akka.serialization.JavaSerializer
),因为父节点的构造函数 . 如果只有一两条消息,我知道我可以编写自己的序列化程序,但是我的应用程序中有很多这样的case类 .
有没有简单的方法来使用远程演员传递这种对象?
2 回答
如果你像这样重组,事情就会奏效:
我通常尝试使用case类远离类继承 . 如果我需要能够将一组案例类作为抽象类型引用,我会使用特征 .
就像cmbaxter的答案所指出的那样,这种模式,其中case类的超类没有no-arg构造函数,在反序列化时会导致
InvalidClassException
. 根据cmbaxter的回答,避免这种模式是一种解决方案 .但这种模式有什么不对?原因记录在Serializable的API文档中:
所以问题是
class A
没有no-arg构造函数,而且它不是Serializable
. 所以一个简单的解决方案就是让它成为Serializable
!