2013-06-25 16 views
6

Próbuję wysłać wiadomość za pomocą akka zdalnych aktorów, gdzie klasa case jest podklasą superklasy biorącej argument w swoim konstruktorze.Akka zdalnych aktorów, superklasa bez domyślnego konstruktora

Oto minimalny przykład odtworzyć 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://[email protected]: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") 
    } 
} 

Po uruchomieniu tego kodu, pojawia się następujący błąd:

[ERROR] [06/26/2013 02:53:16.132] [Receiver-9] 
[NettyRemoteTransport(akka://[email protected]:2552)] 
[email protected]://[email protected]:2552] Error[java.io.InvalidClassException: com.tuvistavie.testremote.MessageFoo; no valid constructor] 

Myślę, że to dlatego, że wiadomość nie może zostać rozszeregować (używając akka.serialization.JavaSerializer), z powodu konstruktora rodziców. Gdyby to była tylko jedna lub dwie wiadomości, wiem, że mógłbym napisać własny serializator, ale mam mnóstwo takich przypadków w mojej aplikacji.

Czy istnieje jakiś prosty sposób na przekazanie tego rodzaju obiektu za pomocą zdalnych aktorów?

Odpowiedz

8

Co będzie działać, jeśli zrestrukturyzować tak:

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

ja generalnie spróbować i pobyt z dala od klasy dziedziczenie z klas przypadków. Jeśli potrzebuję móc odnieść się do zestawu klas spraw jako abstrakcyjnego typu, używam zamiast tego cech.

+1

Czy możesz wyjaśnić, co tu się dzieje? Ani pytanie "MessageFoo", ani twoje, nie ma konstruktora no-arg. Dlaczego pracuje się z serializacją Java, a druga nie? –

+0

@ Danielasarabos, klasy przypadków scala można szeregować. Jeśli spojrzysz na wygenerowany kod java dla klasy case, zobaczysz, że spełnia on warunki umowy do serializacji. – cmbaxter

+0

Ale klasa przypadków w pytaniu nie mogła zostać przekształcona do postaci szeregowej, prawda? –

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

jak odpowiedź cmbaxter za zaznacza ten wzór, gdzie nadklasą klasie przypadku nie ma konstruktora nie-Arg, prowadzi do InvalidClassException na deserializacji. Zgodnie z odpowiedzią cmbaxtera unikanie tego schematu jest jednym z rozwiązań.

Co jest jednak nie tak w tym wzorze? Powodem jest udokumentowana w docs API dla Serializable:

To allow subtypes of non-serializable classes to be serialized, the subtype may assume responsibility for saving and restoring the state of the supertype's public, protected, and (if accessible) package fields. The subtype may assume this responsibility only if the class it extends has an accessible no-arg constructor to initialize the class's state. It is an error to declare a class Serializable if this is not the case. The error will be detected at runtime.

Tak więc problem jest to, że class A nie posiada nie-Arg konstruktora, plus nie jest Serializable. Tak więc prostym rozwiązaniem jest uczynienie go Serializable!

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

działa jak urok, szybka wygrana, aby po prostu dodać 'extends' /' with', jak ma to miejsce w przypadku restrukturyzacji do cech. – Brett