2016-08-18 1 views
3

Pourquoi suis-je capable de sérialisez:Pourquoi la sérialisabilité scala diffère-t-elle dans les classes de cas avec les mêmes types de paramètres constructeurs?

// Serialize: OK 
case class ClassWithType2[T:TypeTag](x:T) { 
    val tpe:java.lang.reflect.Type = Util.toJavaClass[T] 
} 

... mais pas

class TypeAware[T:TypeTag]() { 
    val tpe:java.lang.reflect.Type = Util.toJavaClass[T] 
} 

// Serialize: FAIL. 
// No valid constructor for ClassWithType1 
// in: java.io.ObjectStreamClass.checkDeserialize 
case class ClassWithType1[T:TypeTag](x:T) extends TypeAware[T] 

semblent tous deux avoir le même prototype de type constructeur:

[T:TypeTag](x:T) 

et les deux s'étendre scala .Serializable et java.io.Serializable

val s1:Serializable = ClassWithType1(x=123) 
val s2:Serializable = ClassWithType2(x=123) 
val s3:java.io.Serializable = ClassWithType1(x=123) 
val s4:java.io.Serializable = ClassWithType2(x=123) 

Sa là une façon de mettre en œuvre des sous-classes TypeAware que:

  • éviter d'avoir à déclarer dans tpe chaque sous-classe (comme ClassWithType2 fait)?
  • permet à l'objet à sérialiser

Voici le harnais de test

class TypesTest { 

    @Test 
    def serializeTypeTest(): Unit = { 
    val obj2:Object = ClassWithType2(x=123) 
    Util.copyBySerialization(obj2) // Success! 

    val obj1:Object = ClassWithType1(x=123) 
    Util.copyBySerialization(obj1) // Fail 
    } 
} 

object Util { 
    def toJavaClass[T:TypeTag]: Class[_] = { 
    val tpe = typeOf[T] 
    runtimeMirror(tpe.getClass.getClassLoader).runtimeClass(tpe.typeSymbol.asClass) 
    } 

    def copyBySerialization[T](obj: T): T = deserialize(serialize(obj)) 

    def serialize[T](obj: T): Array[Byte] = { 
    val byteOut = new ByteArrayOutputStream() 
    val objOut = new ObjectOutputStream(byteOut) 
    objOut.writeObject(obj) 
    objOut.close() 
    byteOut.close() 
    byteOut.toByteArray 
    } 

    def deserialize[T](bytes: Array[Byte]): T = { 
    val byteIn = new ByteArrayInputStream(bytes) 
    val objIn = new ObjectInputStream(byteIn) 
    val obj = objIn.readObject().asInstanceOf[T] 
    byteIn.close() 
    objIn.close() 
    obj 
    } 

} 
+0

TypeAware ne prolonge pas java.io.Serializable. –

+0

Pourquoi cela serait-il nécessaire? Je demande de sérialiser ClassWithType1, qui prétend être Serializable. NB. La sérialisation échoue car elle ne peut pas trouver un constructeur pour ClassWithType1, pas parce que TypeAware ou ses membres ne peuvent pas être sérialisés (la sérialisation de java.reflect.Type fonctionne correctement). – user48956

+0

Toutes les quelques années, j'essaie de me rafraîchir la mémoire sur la sérialisation Java, mais je ne pense pas que ce soit le cas aujourd'hui. Mais vois ma réponse; le ctor n'est pas nul. –

Répondre

3

Il suffit de citer le Javadoc:

Pour autoriser les sous-types de classes non sérialisables être sérialisé, la Le sous-type peut assumer la responsabilité de sauvegarder et de restaurer l'état du pac public, protégé et (si accessible) du supertype kage champs. Le sous-type peut assumer cette responsabilité uniquement si la classe qu'il comporte possède un constructeur accessible sans-argument pour initialiser l'état de la classe . C'est une erreur de déclarer une classe Serializable si ce n'est pas le cas. L'erreur sera détectée lors de l'exécution.

Le ctor pour TypeAware inclut le paramètre implicite. Editer: une idée consiste à faire de la balise de type un membre. Ou similaire. Il ne sauvegarde pas autant de syntaxe.

abstract class TypeAware { 
    protected def tt: TypeTag[_] 
    def tpe:java.lang.reflect.Type = Util.toJavaClass(tt) 
} 

case class ClassWithType1[T](x:T)(implicit val tt: TypeTag[T]) extends TypeAware 

Edition, plus linx:

tech page

faq

your question

+0

Il semble donc que faire TypeAware étend Serializable corrige cela en ajoutant un constructeur manquant à sa sous-classe. Pas très intuitif, mais je vais le prendre. – user48956

+0

Je suppose que cela vaut la peine de lire les documents si vous devez l'utiliser.Il y a aussi une entrée faq sur la décision d'exiger le trait de marqueur. –