pickling icon indicating copy to clipboard operation
pickling copied to clipboard

val from trait not pickled

Open jcrowley66 opened this issue 7 years ago • 0 comments

Have this trait:

trait TestTrait1 {
  val createdAt = System.currentTimeMillis
  var finishedAt:Long = 0

  def setAsFinished():Unit = finishedAt = System.currentTimeMillis

  override def toString = s"TestTrait[createdAt=$createdAt, finishedAt=$finishedAt]"
}

and this case class:

case class TestCaseClass(int:Int, dbl:Double, str:String, millis:Long = System.currentTimeMillis) extends TestTrait1 

instantiating the case class by:

TestCaseClass(1, 2.0, "String3")

and pickling gives this JSON:

{
  "$type": "pickletests.TestCaseClass",
  "int": 1,
  "dbl": 2.0,
  "str": "String3",
  "millis": "1497970617809",
  "finishedAt": "1497970618823"
}

The createdAt field does not appear in the JSON, and hence upon unpickling is set to a new (different) value. By contrast, the millis field is represented and hence retains the originally assigned value. If createdAt is defined as a var instead of a val then it will appear in the JSON and the correct value is preserved.

Is this a bug or a feature? (In our actual application, createdAt is really an internal uniqueID field, so really do want it declared as a val so that it can never be accidentally modified.)

This was run using 0.11.0-M2, Scala 2.11.8, java 1.8.0_121, the IDE is IntelliJ

The complete test routine and console output is pasted below.

BTW: 0.10.0 throws an exception trying to unpickle, claiming that the var finishedAt is not represented as a Java variable in the class file. Have the same problem in 0.11.0-M2 in our full application, but have not been able to reproduce within an isolated test file.


package pickletests

import scala.pickling._
import scala.pickling.Defaults._
import scala.pickling.json._

/**
  * Created by JCrowley on 6/19/2017.
  */

trait TestTrait1 {
  val createdAt = System.currentTimeMillis
  var finishedAt:Long = 0

  def setAsFinished():Unit = finishedAt = System.currentTimeMillis

  override def toString = s"TestTrait[createdAt=$createdAt, finishedAt=$finishedAt]"
}

case class TestCaseClass(int:Int, dbl:Double, str:String, millis:Long = System.currentTimeMillis) extends TestTrait1 {
  override def toString = s"TestCaseClass[int=$int, dbl=$dbl, str='$str', millis=$millis ${super.toString}]"
}

object PickleVarInTraitTests extends App {

  val test = TestCaseClass(1, 2.0, "String3")

  Thread.sleep(1000)

  test.setAsFinished()

  Console.println(s"\nEnvironment - Scala: ${scala.util.Properties.versionString}  Java: ${System.getProperty("java.version")}\n")

  Console.println("\nOriginal TestCaseClass: " + test.toString + "\n")

  val testPickled = test.pickle
  val testPickledJSON = testPickled.value

  Console.println("JSON pickled: " + testPickledJSON + "\n")

  val testUnpickle = testPickledJSON.unpickle[TestCaseClass]

  Console.println("Success for [TestCaseClass] = " + testUnpickle + "\n")

  val testUnpickle2 = testPickledJSON.unpickle[AnyRef]

  Console.println("Unpickle1 == Unpickle2: " + (testUnpickle == testUnpickle2))
}

----------------------------------- Console Output -------------------------------------

Environment - Scala: version 2.11.8  Java: 1.8.0_121


Original TestCaseClass: TestCaseClass[int=1, dbl=2.0, str='String3', millis=1497970617809 TestTrait[createdAt=1497970617809, finishedAt=1497970618823]]

JSON pickled: {
  "$type": "pickletests.TestCaseClass",
  "int": 1,
  "dbl": 2.0,
  "str": "String3",
  "millis": "1497970617809",
  "finishedAt": "1497970618823"
}

Success for [TestCaseClass] = TestCaseClass[int=1, dbl=2.0, str='String3', millis=1497970617809 TestTrait[createdAt=1497970619494, finishedAt=1497970618823]]

Unpickle1 == Unpickle2: true

Process finished with exit code 0

jcrowley66 avatar Jun 20 '17 15:06 jcrowley66