Akkova removed actors, superclass without default constructor

I am trying to send a message using akka remote participants, where the case class is a subclass of the superclass taking an argument in its constructor.

Here is a minimal example to reproduce the problem:

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") } } 

When I run this code, I get the following error:

 [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] 

I think this is because the message cannot be deserialized (using akka.serialization.JavaSerializer ) due to the parent constructor. If it were only one or two messages that I know, I could write my own serializer, but in my application I have many case classes.

Will there be any easy way to pass this type of objects using remote participants?

+6
source share
2 answers

Everything will work if you restructure:

 trait Foo{ val a:Int } case class MessageFoo(a:Int) extends Foo 

I usually try to stay away from class inheritance with case classes. If I need to be able to refer to a set of case classes as an abstract type, I use traits instead.

+8
source
 class A(a: Int) case class C() extends A(1) 

Like cmbaxter's answer, this template, in which the superclass of the case class does not have a no-arg constructor, raises an InvalidClassException on deserialization. The answer to cmbaxter, avoiding this pattern, is one solution.

But what is wrong with this template? The reason is documented in the API docs for Serializable :

To allow serialization of subtypes of non-serializable classes, the subtype can take responsibility for maintaining and restoring public, protected, and (if available) supertype packages. A subtype can assume this responsibility only if the class that it extends has an available no-arg constructor to initialize the state of the class. Error declaring a Serializable class if it is not. An error will be detected at runtime.

So the problem is that class A does not have a no-arg constructor, plus it is not Serializable . Therefore, a simple solution is to make it Serializable !

 class A(a: Int) extends Serializable case class C() extends A(1) 
+9
source

Source: https://habr.com/ru/post/948091/


All Articles