@transient lazy val field serialization
Asked Answered
S

1

11

I have a problem on Scala. I serialize an instance of class with @transient lazy val field. And then I deserialize it, the field is assigned null. I expect the lazy evaluation after deserialization. What should I do?

Following is a sample code.

object Test {

  def main(args: Array[String]){

    //----------------
    // ClassA - with @transient
    //----------------

    val objA1 = ClassA("world");

    println(objA1);
    // This works as expected as follows:
    //   "Good morning."
    //   "Hello, world"

    saveObject("testA.dat", objA1);

    val objA2 = loadObject("testA.dat").asInstanceOf[ClassA];

    println(objA2);
    // I expect this will work as follows:
    //   "Good morning."
    //   "Hello, world"
    // but actually it works as follows:
    //   "null"



    //----------------
    // ClassB - without @transient
    // this works as expected
    //----------------

    val objB1 = ClassB("world");

    println(objB1);
    // This works as expected as follows:
    //   "Good morning."
    //   "Hello, world"

    saveObject("testB.dat", objB1);

    val objB2 = loadObject("testB.dat").asInstanceOf[ClassB];

    println(objB2);
    // This works as expected as follows:
    //   "Hello, world"

  }

  case class ClassA(name: String){

    @transient private lazy val msg = {
      println("Good morning.");
      "Hello, " + name;
    }

    override def toString = msg;

  }

  case class ClassB(name: String){

    private lazy val msg = {
      println("Good morning.");
      "Hello, " + name;
    }

    override def toString = msg;

  }

  import java.io.FileInputStream;
  import java.io.FileOutputStream;
  import java.io.ObjectInputStream;
  import java.io.ObjectOutputStream;

  def saveObject(fname: String, obj: AnyRef){
    val fop = new FileOutputStream(fname);
    val oop = new ObjectOutputStream(fop);
    try {
      oop.writeObject(obj);
    } finally {
      oop.close();
    }
  }

  def loadObject(fname: String): AnyRef = {
    val fip = new FileInputStream(fname);
    val oip = new ObjectInputStream(fip);
    try {
      oip.readObject();
    } finally {
      oip.close();
    }
  }

}
Spirula answered 23/1, 2011 at 7:48 Comment(0)
M
9

There's a couple of tickets on this in Scala's Trac:

I'd advise you to test against a trunk build of 2.9, as it may already be fixed.

Mussorgsky answered 23/1, 2011 at 11:14 Comment(1)
Just an update that this works fine in Scala 2.10.4. However, I notice it's still broken if the initializer relies on a by-name argument. For example, make ClassA.name be => String and it won't work. (You'll also need to make it a non-case class that extends Serializable, and make name a val.)Project

© 2022 - 2024 — McMap. All rights reserved.