scalacheck icon indicating copy to clipboard operation
scalacheck copied to clipboard

CanBuildFrom/GenTraversableFactory causing serialization issue

Open nevillelyh opened this issue 6 years ago • 4 comments

I can reproduce with the following code on scala 2.12.

import java.io.{ByteArrayOutputStream, ObjectOutputStream}

import org.scalacheck._

object SerDe {
  def main(args: Array[String]): Unit = {
    val oos = new ObjectOutputStream(new ByteArrayOutputStream)

    val arbInt = implicitly[Arbitrary[Int]]
    oos.writeObject(arbInt)

    val arbList = implicitly[Arbitrary[List[Int]]]
    oos.writeObject(arbList)
  }
}

Looks like it's summoning the following implicit in BuildableVersionSpecific.

implicit def buildableCanBuildFrom[T,F,C](implicit c: CanBuildFrom[F,T,C]): Buildable[T,C]

And I can see one for list in SerializableCanBuildFroms

implicit def listCanBuildFrom[T]: CanBuildFrom[List[T], T, List[T]]

But somehow it's not summoned.

Stack trace:

[error] (run-main-2) java.io.NotSerializableException: scala.collection.generic.GenTraversableFactory$$anon$1
[error] java.io.NotSerializableException: scala.collection.generic.GenTraversableFactory$$anon$1
[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) scalacheck / Test / runMain 0s
[error]         at java.io.ObjectOutputStream.writeArray(ObjectOutputStream.java:1378)
[error]         at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1174)
[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.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 magnolia.scalacheck.test.SerDe$.main(SerDe.scala:15)
[error]         at magnolia.scalacheck.test.SerDe.main(SerDe.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)

nevillelyh avatar Oct 24 '19 15:10 nevillelyh

Adding import org.scalacheck.util.SerializableCanBuildFroms._ fixes the issue. Is it by design that they're not in scope?

nevillelyh avatar Oct 24 '19 15:10 nevillelyh

There's a serializability test in ScalaCheck that works. Ironically, the import you needed was removed from that test in d8f1322. I know forking the JVM was needed for the test to work in Scala 2.13, but you're asking about 2.12, so I'm not sure why you need the import.

ashawley avatar Oct 25 '19 16:10 ashawley

That test you linked doesn't cover Arbitrary[List[T]] though, which summons CanBuildFrom transitively. So it was probably an unused import. Forking for 2.13 might be a different issue since CanBuildFrom was replaced with Factory which is serializable.

So it does look like these implicits need to be manually imported.

nevillelyh avatar Oct 28 '19 17:10 nevillelyh

Yes, a test of Arbitrary[List[T]] is missing. Good catch. For that test, it would require that import statement.

ashawley avatar Oct 29 '19 02:10 ashawley