serialVersionUID change between Scala 2.12.6 and 2.12.7?

I’m experiencing a difference when upgrading from Scala 2.12.6 to 2.12.7 that I did not expect – the generated serialVersionUID for a case class changes.

I reproduce it with the following program:

case class TestClass(id: String)

object TestApp {
  def main(args: Array[String]): Unit = {
    val clazz = classOf[TestClass]
    val uid = java.io.ObjectStreamClass.lookup(clazz).getSerialVersionUID
    println(s"Scala version: ${scala.util.Properties.versionNumberString}")
    println(s"serialVersionUID: $uid")

  }
}

When building/running (using IntelliJ) with Scala 2.12.6 the output is:

Scala version: 2.12.6
serialVersionUID: 9052900597686579055

But with Scala 2.12.7 the output is:

Scala version: 2.12.7
serialVersionUID: -204044466025854046

I use JDK version 1.8.0_181.

I would have assumed that the generated UIDs should be unchanged for a patch-level update of Scala. Is this behavior expected? Am I doing something wrong? Is there anything else you would need to understand the situation better?

Best,
Henrik

This might be due to https://github.com/scala/bug/issues/11207 (I haven’t checked).

Thanks @lrytz. Sounds quite likely.

My TestClass when compiled with Scala 2.12.7 has two apply methods:

public static java.lang.Object apply(java.lang.Object);
public static TestClass apply(java.lang.String);

Whereas with Scala 2.12.6 it only has one:

public static TestClass apply(java.lang.String);

And the apply methods would be included in the calculation of serialVersionUID as far as I can understand.

This problem can cause a quite bad experience for people using Akka Persistence with the default Java serialization (which you of course should not, but people do anyway :slight_smile: ). After upgrading to Scala 2.12.7, events written to the event journal may not be readable any longer, and events written will not be readable if you would downgrade back to Scala 2.12.6.

I’m currently working on migrating an Akka Persistence-based application away from Java serialization, and just upgraded the Scala versions to the latest versions without thinking too much about it. That was unfortunate as it made the migration more complicated.

Finally, I’m not too familiar with the development of Scala, but should I report this somewhere else? On the issue you linked to?

/Henrik

It’s my understanding that anyone using Java serialization should be using @SerialVersionUID. Scala 2.x versions are guaranteed to be be binary (api) compatible between versions of x, which is different than serialization compatible.
I agree though that the addition of the Object(Object) method is surprising, and I wonder if it’s a bug or what the motivation for adding it was. It looks like a good way to confuse people.

It was a good way to confuse me at least. :slight_smile:

Going slightly off topic here, but anyway…

Unless Scala adds more guidelines than Java itself does, I guess whether you explicitly specify serialVersionUID depends on your preference. Are you happy with the default scheme where they are generated automatically but break on any source code change? Would rather specify the ID explicitly but then also have to remember updating it whenever you make a change that breaks backwards compatibility? I think the answer to that can differ based on the circumstances.

But if the Scala does not guarantee keeping the serialVersionUID stable, then the “generated automatically” option sounds rather less appealing. :upside_down_face:

Ya, Scala does not guarantee that serialVersionUID is stable. It’s something anyone using standard Java serialization should be aware of. Even if you get lucky and it’s stable between minor versions, it’s much less likely to be stable between major versions.