Dotty: Serialization fails when @transient val is passed to constructor

Created on 25 Sep 2020  路  5Comments  路  Source: lampepfl/dotty

Minimized code

import java.io._

class Config(s: String)

class ConfigException(@transient val config: Config = null)
    extends java.io.Serializable {}

object Main {

  def main(args: Array[String]): Unit = {
    val e =
      new ConfigException(new Config("not serializable"))
    val byteStream = new ByteArrayOutputStream()
    val objectStream = new ObjectOutputStream(byteStream)
    objectStream.writeObject(e)
    objectStream.close()
    val bytes = byteStream.toByteArray()
    val inStream = new ByteArrayInputStream(bytes)
    val inObjectStream = new ObjectInputStream(inStream)
    val copy = inObjectStream.readObject()
    inObjectStream.close()
  }
}

Output

sbt:dotty-simple> run
[info] Compiling 1 Scala source to /Users/eric/workspace/dotty-test/target/scala-0.27/classes ...
[info] running Main 
[error] (run-main-1a) java.io.NotSerializableException: Config
[error] java.io.NotSerializableException: Config
[error]     at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
[error]     at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
[error]     at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
[error]     at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
[error]     at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
[error]     at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
[error]     at Main$.main(Main.scala:15)
[error]     at Main.main(Main.scala)
[error]     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[error]     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[error]     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[error]     at java.lang.reflect.Method.invoke(Method.java:498)
[error] stack trace is suppressed; run last Compile / bgRun for the full output
[error] Nonzero exit code: 1
[error] (Compile / run) Nonzero exit code: 1
[error] Total time: 0 s, completed Sep 25, 2020 11:33:00 AM
sbt:dotty-simple> 

Expectation

In Scala 2, serialization avoids the @transient val so I am thinking it should avoid in Scala 3 too.
Note: If the @transient val or var is in the body of the class, Scala 3 does not try to serialize.

transform scala2 help wanted bug

Most helpful comment

@transient is defined with the meta-annotation @field which lets the compiler know that it needs to be put on the field: https://github.com/scala/scala/blob/8c86b7d7136839538cca0ff8fca50f59437564c0/src/library/scala/transient.scala#L17-L18, but we have almost no support for meta-annotations currently (see https://github.com/scala/scala/blob/2.13.x/src/library/scala/annotation/meta/package.scala for how they're supposed to work) so this isn't trivial to fix. Here's a sketch of what should be done:

In conclusion I really don't want to do this so I hope someone else will :).

All 5 comments

Here is the info about the class. I don't see any flags for @transient, ACC_TRANSIENT? so I think it may be just omitted.

Edit: removed classfile info as javap wasn't run with -private flag so the next comment is better.

Ok, I have confirmed that if the @transient is in the body we get the following:

private final transient Config config;
    descriptor: LConfig;
    flags: ACC_PRIVATE, ACC_FINAL, ACC_TRANSIENT

If the @transient is in the constructor we get the following:

private final Config config;
    descriptor: LConfig;
    flags: ACC_PRIVATE, ACC_FINAL

@transient is defined with the meta-annotation @field which lets the compiler know that it needs to be put on the field: https://github.com/scala/scala/blob/8c86b7d7136839538cca0ff8fca50f59437564c0/src/library/scala/transient.scala#L17-L18, but we have almost no support for meta-annotations currently (see https://github.com/scala/scala/blob/2.13.x/src/library/scala/annotation/meta/package.scala for how they're supposed to work) so this isn't trivial to fix. Here's a sketch of what should be done:

In conclusion I really don't want to do this so I hope someone else will :).

Thank-you. With all that research it would seem that coderbot could do it.

Wow, very cool - thanks.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

andreaTP picture andreaTP  路  3Comments

liufengyun picture liufengyun  路  3Comments

travisbrown picture travisbrown  路  3Comments

adamgfraser picture adamgfraser  路  3Comments

smarter picture smarter  路  3Comments