Search code examples
scalaserializationsingletonscala-3

How can I serialize a scala singleton object?


I am trying to serialize a scala singleton object using the built in java object serialization library.

Here's an example of the serializer program:

  object potato extends Serializable {
    var dirt = 5
  }

  def main(args: Array[String]): Unit = {

    val fileName = "potato.sav"
    val potatoOutputStream = new ObjectOutputStream(new FileOutputStream(fileName))
    potato.dirt = 12345
    potatoOutputStream.writeObject(potato)
    potatoOutputStream.close()
}

and here's an example of the deserializer program:

  object potato extends Serializable {
    var dirt = 5
  }

  def main(args: Array[String]): Unit = {

    val fileName = "potato.sav"
    val potatoInputStream = new ObjectInputStream(new FileInputStream(fileName))
    val p = potatoInputStream.readObject.asInstanceOf[potato.type]
    println("potato dirt quantity " + p.dirt)
  }

this prints 5 instead of the expected 12345. I've looked at potato.sav in a hex editor and the number 12345 doesn't even show up, it appears to be a 'scala.runtime.ModuleSerializationProxy' and doesn't contain any field data. In fact, changing any of the numbers in the initializer or the main function results in a byte-for-byte identical serialized file :(

I kind of understand why this might be happening, and that deserializing a singleton object can't (or shouldn't) create another instance, but I would really like to find a way to make this, or something similar work. I don't need to use the built in serialization library, but I need a solution that doesn't require writing a custom serializer/deserializer for each individual singleton object.

Any help would be appreciated. Thanks!

edit: I am using objects here because I want many instances of anonymous subclasses of a certain type, each with custom logic for a DSL.

Unfortunately it seems like using object makes them not serializable because they are implemented as static classes, which java won't serialize. Structural types are out too because in scala 3 you can't access mutable state anymore as some kind of new and unexplained restriction, not to mention the performance problems with structural types.


Solution

  • Ended up writing my own object serialization routine with some help from apache reflection utils. It's not pretty but it works.

    def SerializeMembers(oos: ObjectOutputStream): Unit = {
        val fields = FieldUtils.getAllFields(getClass)
        for (f <- fields) {
            val modifiers = f.getModifiers
            val isNotFinal = (modifiers & Modifier.FINAL) == 0
            if (isNotFinal) {
                f.setAccessible(true)
                oos.writeObject(f.get(this))
            }
        }
    }
    
    def DeserialzeMembers(ois: ObjectInputStream): Unit = {
        val fields = FieldUtils.getAllFields(getClass)
        for (f <- fields) {
            val modifiers = f.getModifiers
            val isNotFinal = (modifiers & Modifier.FINAL) == 0
            if (isNotFinal) {
                f.setAccessible(true)
                val obj = ois.readObject()
                f.set(this, obj)
            }
        }
    }