Open
Description
where Node
is another serializable class.
Following test cases prove my point. (please see the comments for more clarification.)
// Node.scala
case class Node(i: Int)
case class Test2() {
val roots = List(Node(10))
}
case class Test3() {
val roots = List(Set(0))
}
```s
```scala
// FailingTest.scala
import org.scalatest.FunSuite
class FailingTest extends FunSuite {
/** Following test fails with a confusing exception namely "java.lang.ClassCastException:
* cannot assign instance of scala.collection.immutable.List$SerializationProxy
* to field Test2.roots of type scala.collection.immutable.List
* in instance of Test2"
*
* This exception is in one sense correct but not the root cause of the problem.
*
* The real exception gets thrown at ObjectStreamClass.java:1062
* "java.lang.ClassNotFoundException: Node" which is the real cause of the
* problem. I was wondering why this does not get to the surface, i.e. why we can not
* see this exception but the other misleading exception above. This happens somewhere
* at ObjectInputStream.java:1910, where it follows some circular logic and gets lost.
* I was wondering if something could be changed and real exception gets to the surface.
*/
test("fails with exception while deserializing.") {
val test2 = new Test2()
SerDe.save("/tmp/test2", test2)
val deserialized = SerDe.load2("/tmp/test2")
}
test("Same test as above but passes by supplying the classloader while deserialize.") {
val test2 = new Test2()
SerDe.save("/tmp/test2", test2)
val deserialized = SerDe.load("/tmp/test2")
}
test("Should serialize and deserialize fine. Does not need explicit classloader") {
val test3 = new Test3()
SerDe.save("/tmp/test3", test3)
val deserialized = SerDe.load2("/tmp/test3")
}
}
// SerDe.scala
import java.io._
object SerDe {
val loader = Thread.currentThread().getContextClassLoader
def load(path: String) = {
val objIn = new ObjectInputStream(new FileInputStream(path)) {
override def resolveClass(desc: ObjectStreamClass): Class[_] =
Class.forName(desc.getName, false, loader)
}
objIn.readObject
}
/** Without specifying the classloader. */
def load2(path: String) = {
val objIn = new ObjectInputStream(new FileInputStream(path))
objIn.readObject
}
def save(path: String, instance: Any): Unit = {
val oos = new ObjectOutputStream(new FileOutputStream(path))
oos.writeObject(instance)
oos.close()
}
}
The idea of the above example was to only illustrate that, in scenario where there are classloader issues the error seen during deserialization is far from reality and does not give any idea of what really happened. Since there are several other ways there may be a CNF during deserialization just by fixing the classloader as above the problem is not eliminated. I hope this clears, why this exists as a bug.
I was actually trying to fix it, but not sure if I am thinking in the right direction. Any help would be appreciated.