Even trivial serialization examples in Scala don't work. Why?

class, exception, scala, serialization

Solution

Note that `@serializable` scaladoc tells that it is deprecated since 2.9.0:

Deprecated (Since version 2.9.0) instead of @serializable class C, use class C extends Serializable

So you just have to use `Serializable` trait:

class Person(val age: Int) extends Serializable

This works for me (type `:paste` in REPL and paste these lines):

import java.io.{ObjectOutputStream, ObjectInputStream}
import java.io.{FileOutputStream, FileInputStream}

class Person(val age: Int) extends Serializable {
  override def toString = s"Person($age)"
}

val os = new ObjectOutputStream(new FileOutputStream("/tmp/example.dat"))
os.writeObject(new Person(22))
os.close()

val is = new ObjectInputStream(new FileInputStream("/tmp/example.dat"))
val obj = is.readObject()
is.close()
obj

This is the output:

// Exiting paste mode, now interpreting.

import java.io.{ObjectOutputStream, ObjectInputStream}
import java.io.{FileOutputStream, FileInputStream}
defined class Person
os: java.io.ObjectOutputStream = java.io.ObjectOutputStream@5126abfd
is: java.io.ObjectInputStream = java.io.ObjectInputStream@41e598aa
obj: Object = Person(22)
res8: Object = Person(22)

So, you can see, the [de]serialization attempt was successful.

Edit (on why you're getting `NotSerializableException` when you run Scala script from file)

I've put my code into a file and tried to run it via `scala test.scala` and got exactly the same error as you. Here is my speculation on why it happens.

According to the stack trace a weird class `Main$$anon$1` is not serializable. Logical question is: why it is there in the first place? We're trying to serialize `Person` after all, not something weird.

Scala script is special in that it is implicitly wrapped into an object called `Main`. This is indicated by the stack trace:

at Main$$anon$1.<init>(test.scala:9)
at Main$.main(test.scala:1)
at Main.main(test.scala)

The names here suggest that `Main.main` static method is the program entry point, and this method delegates to `Main$.main` instance method (`object`'s class is named after the object but with `$` appended). This instance method in turn tries to create an instance of a class `Main$$anon$1`. As far as I remember, anonymous classes are named that way.

Now, let's try to find exact `Person` class name (run this as Scala script):

class Person(val age: Int) extends Serializable {
  override def toString = s"Person($age)"
}

println(new Person(22).getClass)

This prints something I was expecting:

class Main$$anon$1$Person

This means that `Person` is not a top-level class; instead it is a nested class defined in the anonymous class generated by the compiler! So in fact we have something like this:

object Main {
  def main(args: Array[String]) {
    new {  // this is where Main$$anon$1 is generated, and the following code is its constructor body
      class Person(val age: Int) extends Serializable { ... }
      // all other definitions
    }
  }
}

But in Scala all nested classes are something called "nested non-static" (or "inner") classes in Java. This means that these classes always contain an implicit reference to an instance of their enclosing class. In this case, enclosing class is `Main$$anon$1`. Because of that when Java serializer tries to serialize `Person`, it transitively encounters an instance of `Main$$anon$1` and tries to serialize it, but since it is not `Serializable`, the process fails. BTW, serializing non-static inner classes is a notorious thing in Java world, it is known to cause problems like this one.

As for why it works in REPL, it seems that in REPL declared classes somehow do not end up as inner ones, so they don't have any implicit fields. Hence serialization works normally for them.

Problem

I am trying the simplest possible serialization examples of a class: ``` @serializable class Person(age:Int) {} val fred = new Person(45) import java.io._ val out = new ObjectOutputStream(new FileOutputStream("test.obj")) out.writeObject(fred) out.close() ``` This throws exception "java.io.NotSerializableException: Main$$anon$1$Person" on me. Why? Is there a simple serialization example? I also tried ``` @serializable class Person(nm:String) { private val name:String=nm } val fred = new Person("Fred") ... ``` and tried to remove `@serializable` and some other permutations. The file "test.obj" is created, over 2Kb in size and has plausible contents. EDIT: Reading the "test.obj" back in (from the 2nd answer below) causes Welcome to Scala version 2.10.3 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_51). Type in expressions to have them evaluated. Type :help for more information. scala> import java.io._ import java.io._ scala> val fis = new FileInputStream( "test.obj" ) fis: java.io.FileInputStream = java.io.FileInputStream@716ad1b3 scala> val oin = new ObjectInputStream( fis ) oin: java.io.ObjectInputStream = java.io.ObjectInputStream@1f927f0a scala> val p= oin.readObject java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: Main$$anon$1 at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1354) at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1990) at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1915) at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1798) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370) at .(:12) at .() at .(:7) at .() at $print() at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:734) at scala.tools.nsc.interpreter.IMain$Request.loadAndRun(IMain.scala:983) at scala.tools.nsc.interpreter.IMain.loadAndRunReq$1(IMain.scala:573) at scala.tools.nsc.interpreter.IMain.interpret(IMain.scala:604) at scala.tools.nsc.interpreter.IMain.interpret(IMain.scala:568) at scala.tools.nsc.interpreter.ILoop.reallyInterpret$1(ILoop.scala:756) at scala.tools.nsc.interpreter.ILoop.interpretStartingWith(ILoop.scala:801) at scala.tools.nsc.interpreter.ILoop.command(ILoop.scala:713) at scala.tools.nsc.interpreter.ILoop.processLine$1(ILoop.scala:577) at scala.tools.nsc.interpreter.ILoop.innerLoop$1(ILoop.scala:584) at scala.tools.nsc.interpreter.ILoop.loop(ILoop.scala:587) at scala.tools.nsc.interpreter.ILoop$$anonfun$process$1.apply$mcZ$sp(ILoop.scala:878) at scala.tools.nsc.interpreter.ILoop$$anonfun$process$1.apply(ILoop.scala:833) at scala.tools.nsc.interpreter.ILoop$$anonfun$process$1.apply(ILoop.scala:833) at scala.tools.nsc.util.ScalaClassLoader$.savingContextLoader(ScalaClassLoader.scala:135) at scala.tools.nsc.interpreter.ILoop.process(ILoop.scala:833) at scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:83) at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:96) at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:105) at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala) Caused by: java.io.NotSerializableException: Main$$anon$1 at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1183) at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1547) at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1508) at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1431) at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1177) at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:347) at Main$$anon$1.(a.scala:11) at Main$.main(a.scala:1) at Main.main(a.scala) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at scala.tools.nsc.util.ScalaClassLoader$$anonfun$run$1.apply(ScalaClassLoader.scala:71) at scala.tools.nsc.util.ScalaClassLoader$class.asContext(ScalaClassLoader.scala:31) at scala.tools.nsc.util.ScalaClassLoader$URLClassLoader.asContext(ScalaClassLoader.scala:139) at scala.tools.nsc.util.ScalaClassLoader$class.run(ScalaClassLoader.scala:71) at scala.tools.nsc.util.ScalaClassLoader$URLClassLoader.run(ScalaClassLoader.scala:139) at scala.tools.nsc.CommonRunner$class.run(ObjectRunner.scala:28) at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:45) at scala.tools.nsc.CommonRunner$class.runAndCatch(ObjectRunner.scala:35) at scala.tools.nsc.ObjectRunner$.runAndCatch(ObjectRunner.scala:45) at scala.tools.nsc.ScriptRunner.scala$tools$nsc$ScriptRunner$$runCompiled(ScriptRunner.scala:171) at scala.tools.nsc.ScriptRunner$$anonfun$runScript$1.apply(ScriptRunner.scala:188) at scala.tools.nsc.ScriptRunner$$anonfun$runScript$1.apply(ScriptRunner.scala:188) at scala.tools.nsc.ScriptRunner$$anonfun$withCompiledScript$1.apply$mcZ$sp(ScriptRunner.scala:157) at scala.tools.nsc.ScriptRunner$$anonfun$withCompiledScript$1.apply(ScriptRunner.scala:131) at scala.tools.nsc.ScriptRunner$$anonfun$withCompiledScript$1.apply(ScriptRunner.scala:131) at scala.tools.nsc.util.package$.trackingThreads(package.scala:51) at scala.tools.nsc.util.package$.waitingForThreads(package.scala:35) at scala.tools.nsc.ScriptRunner.withCompiledScript(ScriptRunner.scala:130) at scala.tools.nsc.ScriptRunner.runScript(ScriptRunner.scala:188) at scala.tools.nsc.ScriptRunner.runScriptAndCatch(ScriptRunner.scala:201) at scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:76) ... 3 more

Original source