2010-11-01 10 views
9

Juego con este ejemplo http://scala.sygneca.com/code/remoteactors para aprender cómo funcionan los actores remotos en Scala (2.8.0). En particular modifiqué ligeramente cómo los mensajes enviados por los actores se definen como sigue:¿Por qué no se pueden serializar objetos y clases de casos?

sealed trait Event extends Serializable 
case object Ping extends Event 
case object Pong extends Event 
case object Quit extends Event 

y todo funciona como se esperaba. Desafortunadamente si defino los eventos como clases de casos en lugar de objetos de casos como en:

sealed trait Event extends Serializable 
case class Ping extends Event 
case class Pong extends Event 
case class Quit extends Event 

mi ejemplo deja de funcionar. En más detalle, parece que, aunque los objetos del caso son serializables, las clases de casos no lo son. De hecho, cuando trato de ejecutar mi ejemplo con esta última modificación consigo la siguiente excepción:

[email protected]: caught java.io.NotSerializableException: scalachat.remote.Ping$ 
java.io.NotSerializableException: scalachat.remote.Ping$ 
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1156) 
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:326) 
    at scala.actors.remote.JavaSerializer.serialize(JavaSerializer.scala:46) 
    at scala.actors.remote.NetKernel.namedSend(NetKernel.scala:38) 
    at scala.actors.remote.NetKernel.forward(NetKernel.scala:71) 
    at scala.actors.remote.DelegateActor$$anonfun$act$1$$anonfun$apply$1.apply(Proxy.scala:182) 
    at scala.actors.remote.DelegateActor$$anonfun$act$1$$anonfun$apply$1.apply(Proxy.scala:123) 
    at scala.actors.ReactorTask.run(ReactorTask.scala:34) 
    at scala.actors.ReactorTask.compute(ReactorTask.scala:66) 
    at scala.concurrent.forkjoin.RecursiveAction.exec(RecursiveAction.java:147) 
    at scala.concurrent.forkjoin.ForkJoinTask.quietlyExec(ForkJoinTask.java:422) 
    at scala.concurrent.forkjoin.ForkJoinWorkerThread.mainLoop(ForkJoinWorkerThread.java:340) 
    at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:325) 

¿Hay una razón por qué los objetos de casos se pueden hacer clases serializables y casos no se puede? ¿Hay alguna forma de que mi ejemplo funcione con clases de casos?

Editar: según lo sugerido por Victor y confirmado por Aaron, estoy enviando el objeto complementario como mensaje en lugar de la clase. Además de inspeccionar el código compilado con javap parece evidente que mientras que la clase es serializable:

public class scalachat.remote.Ping extends java.lang.Object implements scalachat.remote.Event,java.io.Serializable,scala.ScalaObject,scala.Product 

el objeto compañero no es:

public final class scalachat.remote.Ping$ extends scala.runtime.AbstractFunction0 implements scala.ScalaObject 

Ahora la pregunta es: ¿Cómo puedo especificar que quiero usar la clase en lugar del objeto compañero? También agregué un par de paréntesis vacíos cuando envío el mensaje sugerido por Aaron como en:

pong ! Ping() 

pero nada ha cambiado. Al final me También se ha añadido un parámetro falso a la clase caso

case class Ping(i: Int) extends Event 

enviando el mensaje como:

pong ! Ping(0) 

pero sin experimentar ninguna diferencia todavía. ¿Cualquier sugerencia?

+2

Por lo que yo sé, no es necesario implementar explícitamente la interfaz 'Serializable', ya que ambas clases de casos y objetos de caso ya están implícitamente usando' @ serializable' (es simplemente azucarado). Compila tu código con 'scalac -print' para ver el código eliminado, puede ayudarte a descubrir cuál es el problema. Una pequeña prueba en el REPL muestra que las clases de casos pueden ser [deserializadas] contra 2.8.0. –

+0

http://gist.github.com/657953 –

+0

http://scala-programming-language.1934581.n4.nabble.com/deprecate-serializable-td3002109.html –

Respuesta

14
@serializable case class Foo 

También me sorprendió que los objetos del caso fueran serializables por defecto.

Editar: Después de leer la excepción adecuadamente sospecho que:

usted está tratando de enviar el objeto compañero generada caso de la clase sobre el alambre, en lugar de una instancia de la clase caso.

+9

Las clases de casos también se pueden serializar de manera predeterminada. Por cierto, en los fragmentos de las clases de casos anteriores se hereda de 'Serializable', que en la mayoría de los casos es igual al uso de la anotación' @ serializable' –

+7

En general, no se recomienda usar '@ serializable', y probablemente se desaprobe pronto: http://scala-programming-language.1934581.n4.nabble.com/deprecate-serializable-td3002109.html –

+0

Lo siento, pero creo que no está respondiendo a mi pregunta. La anotación @serializable y la extensión de la interfaz Serializable deberían ser casi iguales (incluso si la primera aparentemente va a estar obsoleta) De todos modos, también traté de usar la anotación @serializable y experimenté el mismo efecto: el objeto del caso se puede serializar mientras que las clases de casos no pueden. En otras palabras, incluso para escribir la clase de caso @serializable, Ping no funciona en mi ejemplo. –

4

Las clases de casos sin parámetros no tienen sentido y están en desuso. Y no veo Serializable en Scala, solo serializable. ¿Funciona si arreglas estas cosas?

+2

Quería usar clases de casos exactamente porque necesitaba agregar algunos parámetros a ellos. La interfaz Serializable es en realidad la que está en el paquete java.io y usar la anotación @serializable hace lo mismo y da el mismo problema que experimenté. Además, por lo que sé, la anotación @serializable va a estar en desuso y esta es la única razón por la que evité usarla. –

+0

@Mario Me refiero a extender scala.serializable, que es la forma recomendada de hacerlo. –

Cuestiones relacionadas