Skip to content
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

Class not found on deserializing in REPL, but works outside of REPL #2403

Closed
scabug opened this issue Sep 28, 2009 · 4 comments
Closed

Class not found on deserializing in REPL, but works outside of REPL #2403

scabug opened this issue Sep 28, 2009 · 4 comments
Assignees
Labels

Comments

@scabug
Copy link

scabug commented Sep 28, 2009

The attached program, which serializes then deserializes an object, runs as expected standalone, but complains that it can't find one of the classes (already loaded!) when running under the REPL.

To reproduce:

scalac -cp . SerialTest.scala

scala -cp . SerialTest

before: Land(8,List(Road(1000,2400,4)),2500,4.0)

after: Land(8,List(Road(1000,2400,4)),2500,4.0)

scala -cp .

Welcome to Scala version 2.7.6.final (Java HotSpot(TM) Client VM, Java 1.6.0_16).

Type in expressions to have them evaluated.

Type :help for more information.

scala> SerialTest.main(new ArrayString)

before: Land(8,List(Road(1000,2400,4)),2500,4.0)

java.lang.ClassNotFoundException: Road
at java.net.URLClassLoader$$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang....

@scabug
Copy link
Author

scabug commented Sep 28, 2009

Imported From: https://issues.scala-lang.org/browse/SI-2403?orig=1
Reporter: archontophoenix
Attachments:

@scabug
Copy link
Author

scabug commented May 10, 2010

archontophoenix said:
Still reproducible under 2.8.0.RC2.

@scabug
Copy link
Author

scabug commented Jul 11, 2010

@harrah said:
Summary: you need a custom subclass of !ObjectInputStream to explicitly specify the class loader to use for deserialization:

val ois = new ObjectInputStream(new FileInputStream(fileName)) {
  override def resolveClass(desc: java.io.ObjectStreamClass): Class[_] = {
    try { Class.forName(desc.getName, false, getClass.getClassLoader) }
    catch { case ex: ClassNotFoundException => super.resolveClass(desc) }
  }
}

The reason is the way that !ObjectInputStream tries to autodetect the class loader to use for deserializing. It searches the stack for the method defined in the first non-null class loader and uses that class loader. The first non-null class loader in your case comes from the stack frame:

at scala.collection.immutable.$$colon$$colon.readObject(List.scala:419)

This is because List overrides readObject and gets called during deserialization. So the class loader for List is used by !ObjectInputStream to resolve classes.

In standalone mode, the Scala class loader is the one that defines your application classes as well and so your classes are found during deserialization. In the REPL, the application classes are loaded in a child class loader of the Scala class loader and so the application classes aren't found by !ObjectInputStream.

The REPL should not work around the fragile autodetection behavior in !ObjectInputStream, when it seems to me that the class loader to use for deserialization should be explicitly provided by the user as standard practice. (I don't know if it is standard practice, but it should be.) It is unfortunate that specifying the class loader to use requires a custom subclass and is not just an argument to !ObjectInputStream.

Note that even if the class loaders were the same as in standalone, a call to readObject from the REPL (instead of from compiled code) would show this same problem because code entered in the REPL is itself in a child class loader.

@scabug scabug closed this as completed May 18, 2011
@scabug
Copy link
Author

scabug commented Dec 4, 2012

Michael Schmitz (schmmd) said:
Just a note, this still applies to 2.9.2. The custom ObjectInputSTream that Mark Harrah suggests works fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants