scala / pickling

Fast, customizable, boilerplate-free pickling support for Scala
lampwww.epfl.ch/~hmiller/pickling
BSD 3-Clause "New" or "Revised" License
831 stars 79 forks source link

Issue with Play's classloader #330

Open oscar-broman opened 9 years ago

oscar-broman commented 9 years ago

When Play is running with hot reloating (sbt run), pickling can't load a very simple, sealed class.

play.api.Application$$anon$1: Execution exception[[RuntimeException: java.lang.ExceptionInInitializerError]]
    at play.api.Application$class.handleError(Application.scala:296) ~[play_2.11-2.3.8.jar:2.3.8]
    at play.api.DefaultApplication.handleError(Application.scala:402) [play_2.11-2.3.8.jar:2.3.8]
    at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$14$$anonfun$apply$1.applyOrElse(PlayDefaultUpstreamHandler.scala:205) [play_2.11-2.3.8.jar:2.3.8]
    at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$14$$anonfun$apply$1.applyOrElse(PlayDefaultUpstreamHandler.scala:202) [play_2.11-2.3.8.jar:2.3.8]
    at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:36) [scala-library-2.11.6.jar:na]
Caused by: java.lang.RuntimeException: java.lang.ExceptionInInitializerError
    at play.api.mvc.ActionBuilder$$anon$1.apply(Action.scala:523) ~[play_2.11-2.3.8.jar:2.3.8]
    at play.api.mvc.Action$$anonfun$apply$1$$anonfun$apply$4$$anonfun$apply$5.apply(Action.scala:130) ~[play_2.11-2.3.8.jar:2.3.8]
    at play.api.mvc.Action$$anonfun$apply$1$$anonfun$apply$4$$anonfun$apply$5.apply(Action.scala:130) ~[play_2.11-2.3.8.jar:2.3.8]
    at play.utils.Threads$.withContextClassLoader(Threads.scala:21) ~[play_2.11-2.3.8.jar:2.3.8]
    at play.api.mvc.Action$$anonfun$apply$1$$anonfun$apply$4.apply(Action.scala:129) ~[play_2.11-2.3.8.jar:2.3.8]
Caused by: java.lang.ExceptionInInitializerError: null
    at controllers.DrugBank$$anonfun$search$1.apply(DrugBank.scala:36) ~[classes/:na]
    at controllers.DrugBank$$anonfun$search$1.apply(DrugBank.scala:31) ~[classes/:na]
    at play.api.mvc.ActionBuilder$$anonfun$apply$16.apply(Action.scala:433) ~[play_2.11-2.3.8.jar:2.3.8]
    at play.api.mvc.ActionBuilder$$anonfun$apply$16.apply(Action.scala:432) ~[play_2.11-2.3.8.jar:2.3.8]
    at play.api.mvc.Action$.invokeBlock(Action.scala:556) ~[play_2.11-2.3.8.jar:2.3.8]
Caused by: java.lang.RuntimeException: error: cannot find class or module with type name 'models.Ingredient'
full type string: 'models.Ingredient'
    at scala.sys.package$.error(package.scala:27) ~[scala-library-2.11.6.jar:na]
    at scala.pickling.internal.package$.liftedTree1$1(package.scala:59) ~[scala-pickling_2.11-0.10.0.jar:0.10.0]
    at scala.pickling.internal.package$.typeFromString(package.scala:54) ~[scala-pickling_2.11-0.10.0.jar:0.10.0]
    at scala.pickling.FastTypeTag$$anon$2.tpe$lzycompute(FastTags.scala:141) ~[scala-pickling_2.11-0.10.0.jar:0.10.0]
    at scala.pickling.FastTypeTag$$anon$2.tpe(FastTags.scala:141) ~[scala-pickling_2.11-0.10.0.jar:0.10.0]

The class is declared in another file as such:

sealed class Ingredient(name: String, id: Option[String])
oscar-broman commented 9 years ago

The reason this happened was I did streamPickle.unpickle[Any] followed by pattern matching. It worked when it was used via the console or in production, but not during dev mode. Being explicit about what I want to unpickle works in all modes.

eed3si9n commented 9 years ago

@phaller, @heathermiller Is this a known behavior that can be solved by a stoke of a pen (or a membrane keyboard)?

jsuereth commented 8 years ago

This is a general issue with all serialization frameworks that use any form of runtime reflection in the presence of classloaders (e.g. ObjectInputStream). What you have to do is set the currentMirror in the internal package of pickling to the appropriate one so pickling can find your classes. Otherwise, pickling assumes System classloader (or current thread context classloader) which is probably wrong for play dev-mode.

I think we'll have to doucment this usage explicitly and provide some nice hooks for dealing with this issue.

jsuereth commented 8 years ago

Also, the 0.11.x branch should be removing the need for reflection on pickling tags, whcih MAY help solve your issue if you can compile with staticOnly imported.