Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does serialization of lazy fields work?

I know the benefits of lazy fields when a postponed evaluation of values is needed for some reasons. I was wondering what was the behavior of lazy fields in terms of serialization.

Consider the following class.

class MyClass {
  lazy val myLazyVal = {...}
  ...
}

Questions:

  • If an instance of MyClass is serialized, does the lazy field get serialized too ?
  • Does the behavior of serialization change if the field has been accessed or not before the serialization ? I mean, if I don't cause the evaluation of the field, is it considered as null ?
  • Does the serialization mechanism provoke an implicit evaluation of the lazy field ?
  • Is there a simple way to avoid the serialization of the variable and getting the value recomputed one more time lazily after the deserialization ? This should happen independently from the evaluation of the field.
like image 526
Nicola Ferraro Avatar asked Jan 10 '15 23:01

Nicola Ferraro


1 Answers

Answers

  1. Yes if field was already initialized, if not you can tread it as a method. Value is not computed -> not serialized, but available after de serialization.
  2. If you didn't touch field it's serialized almost as it's a simple 'def' method, you don't need it's type to be serializable itself, it will be recalculated after de-serialization
  3. No
  4. You can add @transient before lazy val definition in my code example, as I understand it will do exactly what you want

Code to prove

object LazySerializationTest extends App {

  def serialize(obj: Any): Array[Byte] = {
    val bytes = new ByteArrayOutputStream()
    val out = new ObjectOutputStream(bytes)
    out.writeObject(obj)
    out.close()
    bytes.toByteArray
  }

  def deSerialise(bytes: Array[Byte]): MyClass = {
    new ObjectInputStream(new ByteArrayInputStream(bytes)).
      readObject().asInstanceOf[MyClass]
  }

  def test(obj: MyClass): Unit = {
    val bytes = serialize(obj)
    val fromBytes = deSerialise(bytes)

    println(s"Original cnt = ${obj.x.cnt}")
    println(s"De Serialized cnt = ${fromBytes.x.cnt}")
  }

  object X {
    val cnt = new AtomicInteger()
  }

  class X {
    // Not Serializable
    val cnt = X.cnt.incrementAndGet
    println(s"Create instance of X #$cnt")
  }

  class MyClass extends Serializable {
    lazy val x = new X
  }

  // Not initialized
  val mc1 = new MyClass
  test(mc1)

  // Force lazy evaluation
  val mc2 = new MyClass
  mc2.x
  test(mc2) // Failed with NotSerializableException

}
like image 106
Eugene Zhulenev Avatar answered Oct 03 '22 01:10

Eugene Zhulenev