Skip to content

Serializing val that refers to another val captures enclosing class #8033

@travisbrown

Description

@travisbrown

minimized code

trait Okay extends Serializable {
  def okay: Okay
}

class Foo {
  def okay1: Okay = new Okay() {
    val okay: Okay = this
  }
  def okay2: Okay = new Okay {
    val okay: Okay = okay1
  }
}

object Test {
  def main(args: Array[String]): Unit = {
    val foo = new Foo
    println(roundTrip(foo.okay1))
    println(roundTrip(foo.okay2))
  }

  def roundTrip[A](a: A): A = {
    import java.io._

    val aos = new ByteArrayOutputStream()
    val oos = new ObjectOutputStream(aos)
    oos.writeObject(a)
    oos.close()
    val ais = new ByteArrayInputStream(aos.toByteArray())
    val ois: ObjectInputStream = new ObjectInputStream(ais)
    val newA = ois.readObject()
    ois.close()
    newA.asInstanceOf[A]
  }
}
Compiles but fails at runtime
Foo$$anon$1@10234dd6
Exception in thread "main" java.io.NotSerializableException: Foo
	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
	at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
	at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
	at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
	at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
	at Test$.roundTrip(Test.scala:26)
	at Test$.main(Test.scala:18)
	at Test.main(Test.scala)

expectation

This is minimisation from a failing test in Cats, where this arrangement has never been a problem in Scala 2, and the code above runs fine on Scala 2:

Foo$$anon$1@fc3b81d0
Foo$$anon$2@16d6d0a3

Note that if you change val okay in okay2 to a def, you see the same error on Scala 2 and Dotty.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions