Skip to content

2.12: case objects are not serializable when extending class #13003

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
RustedBones opened this issue Jun 4, 2024 · 2 comments
Closed

2.12: case objects are not serializable when extending class #13003

RustedBones opened this issue Jun 4, 2024 · 2 comments

Comments

@RustedBones
Copy link

when declaring case objects that extends class instead of trait, serialization fails with scala 2.12.
case objects are supposed to be serializable.

Reproduction steps

Scala version: 2.12.19 (also testing on 2.12.x scala branch)

package scala

import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4

import java.io.{ByteArrayInputStream, ByteArrayOutputStream, ObjectInputStream, ObjectOutputStream}

sealed abstract class Status(val code: Int)
case object On extends Status(1)
case object Off extends Status(0)

@RunWith(classOf[JUnit4])
class CaseObjectSerializationTest {

  @Test
  def canSerializeMatchError = {
    val barrayOut = new ByteArrayOutputStream()
    new ObjectOutputStream(barrayOut).writeObject(On)
    val barrayIn = new ByteArrayInputStream(barrayOut.toByteArray)
    val status = new ObjectInputStream(barrayIn).readObject().asInstanceOf[Status]
    assert(status == On)
  }
}

Added the test from scala/2.12.x branch: diff

Problem

The test fails with

[error] Test scala.CaseObjectSerializationTest.canSerializeMatchError failed: java.io.InvalidClassException: scala.On$; no valid constructor, took 0.003 sec
[error]     at java.io.ObjectStreamClass$ExceptionInfo.newInvalidClassException(ObjectStreamClass.java:158)
[error]     at java.io.ObjectStreamClass.checkDeserialize(ObjectStreamClass.java:746)
[error]     at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2202)
[error]     at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1687)
[error]     at java.io.ObjectInputStream.readObject(ObjectInputStream.java:489)
[error]     at java.io.ObjectInputStream.readObject(ObjectInputStream.java:447)
[error]     at scala.CaseObjectSerializationTest.canSerializeMatchError(CaseObjectSerializationTest.scala:21)
[error]     at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[error]     at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[error]     at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[error]     at java.lang.reflect.Method.invoke(Method.java:566)
[error]     ...
@RustedBones
Copy link
Author

Did some digging and found the cause of the issue / resolution in scala 2.13 here

  • scala 2.12: case object have synthetic method readResolve. This replaces the de-serialized object with the singleton instance. However, the de-serialization of the original object fails before the replacement. Indeed, a Serializable class must have access to the no-arg constructor of its first non-serializable superclass.

  • scala 2.13: case object have synthetic method writeReplace and uses a proxy to de-serialize the object to return the singleton instance. No failure here.

@SethTisue
Copy link
Member

SethTisue commented Jun 5, 2024

right... fundamentally a duplicate of #10412 , I think? though the failure mode is different. in any case, closing since it's fixed as of 2.13.0 and we don't keep 2.12-only tickets open

@SethTisue SethTisue closed this as not planned Won't fix, can't repro, duplicate, stale Jun 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants