Skip to content
This repository has been archived by the owner on Feb 20, 2019. It is now read-only.

Runtime crash when pickling a FastTypeTag #32

Closed
emchristiansen opened this issue Sep 15, 2013 · 4 comments
Closed

Runtime crash when pickling a FastTypeTag #32

emchristiansen opened this issue Sep 15, 2013 · 4 comments
Assignees
Labels

Comments

@emchristiansen
Copy link
Contributor

Maybe it's a bit weird, but I want to serialize a FastTypeTag, so I can do type verification for a type-safe key-value store I hacked together.
Unfortunately, while the pickling seems to work, unpickling causes a runtime error.

steps

This code:

import scala.pickling._, Defaults._
import scala.pickling.binary._

val ftt = implicitly[FastTypeTag[Int]]
val pickled = ftt.pickle
// Crashes in this line.
val unpickled = pickled.unpickle[FastTypeTag[Int]]

problem

fails with this runtime error:

[info]   scala.reflect.internal.MissingRequirementError: class $anon$1 not found.
[info]   at scala.reflect.internal.MissingRequirementError$.signal(MissingRequirementError.scala:16)
[info]   at scala.reflect.internal.MissingRequirementError$.notFound(MissingRequirementError.scala:17)
[info]   at scala.reflect.internal.Mirrors$RootsBase.ensureClassSymbol(Mirrors.scala:90)
[info]   at scala.reflect.internal.Mirrors$RootsBase.staticClass(Mirrors.scala:119)
[info]   at scala.reflect.internal.Mirrors$RootsBase.staticClass(Mirrors.scala:21)
[info]   at scala.pickling.package$.typeFromString(package.scala:65)
[info]   at scala.pickling.FastTypeTag$.apply(FastTags.scala:56)
[info]   at scalatestextra.TestPersistentMap$$anonfun$1.apply$mcV$sp(testPersistentMap.scala:29)
[info]   at scalatestextra.TestPersistentMap$$anonfun$1.apply(testPersistentMap.scala:26)
[info]   at scalatestextra.TestPersistentMap$$anonfun$1.apply(testPersistentMap.scala:26)
@LBliss
Copy link
Contributor

LBliss commented Oct 17, 2013

Using json instead of binary gives a more explicit error:

Exception in thread "main" scala.reflect.internal.MissingRequirementError: class scala.pickling.FastTypeTag[Nothing]{} in JavaMirror

The class is not found (plus some type erasure). Interesting...
Let's note that the implicit values (implicitly) from FastTypeTag[X] are defined as (anonymous class):

new FastTypeTag[Nothing] {
      def mirror = mirror0
      def tpe = tpe0
      def key = key0
    }

Where FastTypeTag is a trait (!).
Therefore when your try to unpickle it with pickle.unpickle[FastTypeTag[Int]], you're actually trying to instantiate an anonymous class extending a trait.

A more expected exception would be:

Exception in thread "main" java.lang.InstantiationException: [...]

As for example this snippet produces:

  trait A{}
  val test: A = new A{}
  val pickee = test.pickle
  println(pickee)
  val unpickee = pickee.unpickle[A]

However, due to type erasure, it tries to find a corresponding class definition with any matching type [T] to instantiate it with... and do not find any.
Hence your error:

Exception in thread "main" scala.reflect.internal.MissingRequirementError: [...]

As for example this snippet produces ([Int] is erased):

  trait A[Int]{}
  val test: A[Int] = new A[Int]{}
  val pickee = test.pickle
  println(pickee)
  val unpickee = pickee.unpickle[A[Int]]

tl;dr: you cannot unpickle into an anonymous class extending an abstract (trait) type, and due to type erasure the exception is confusing.

EDIT:
This issue #38 is similar (but simpler) I believe.

EDIT2:
If you use a not-anonymous class, it works because unpickle() tags the correct class, but for the anonymous case it doesn't.
This may be solvable by correctly tagging the anonymous class ..?

val test = implicitly[FastTypeTag[Int]]
val pickee = test.pickle
println(pickee)
// val unpickee = pickee.unpickle[FastTypeTag[Int]] // Fails

Output:

JSONPickle({
  "tpe": "scala.pickling.FastTypeTag[Nothing]{}"
})

We can see that the type is strange, some sort of definition of the anonymous class {}. But this type fails to be instantiated at runtime using reflection.

@emchristiansen
Copy link
Contributor Author

Thanks for the detailed response.

I was trying to store a type in a database record for PersistentMap, so I could verify the table type when I connect to it.
As I couldn't serialize a FastTypeTag, I ended up storing a string representation of the type, verifying that types match by invoking the compiler at run-time.
Is there a better way?

@phaller
Copy link
Contributor

phaller commented Jan 10, 2014

The current plan is to provide picklers for FastTypeTags (which will possibly be renamed). It's high up on the to-do list.

@eed3si9n eed3si9n added the bug label Feb 8, 2015
jsuereth added a commit that referenced this issue Aug 13, 2015
Fixes #32 - runtime crash for FastTypeTag pickling.
@jsuereth
Copy link
Contributor

@phaller I just pushed a brancht hat has a FastTypeTag provided pickler (works with runtime pickling too). I'll add some tests and get it into 0.11.x. cc @emchristiansen

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

No branches or pull requests

6 participants