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

Case class deserialized as Map2 for unusual path-dependent types #366

Open
OndrejSpanel opened this issue Feb 21, 2018 · 1 comment
Open

Comments

@OndrejSpanel
Copy link

Deserialization fails in an unexpected way in following code. No exception is thrown, however from field of Container is deserialized as Map instead of XY, the program outputs:

Container(Map(x -> 0.0, y -> 0.0))

package my.jackpack

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper

case class XY(x: Double = 0, y: Double = 0)

trait Abstract {
  type Vector2f

  trait ConstructVector2f {
    def apply(x: Double, y: Double): Vector2f
  }
  implicit val Vector2f: ConstructVector2f
}

object Concrete extends Abstract {
  type Vector2f = XY
  object Vector2f extends ConstructVector2f {
    def apply(x: Double, y: Double) = XY(x, y)
  }
}

object Abstract {
  val Link: Abstract = Concrete
}

import Abstract.Link.Vector2f

case class Container(from: Vector2f)

object Main extends App {

  val mapper = new ObjectMapper with ScalaObjectMapper

  mapper.registerModule(DefaultScalaModule)

  val input = Container(Vector2f(0,0))

  val out = mapper.writeValueAsString(input)

  val loaded = mapper.readValue[Container](out)

  val xy: Vector2f = loaded.from

  println(loaded) // prints "Container(Map(x -> 0.0, y -> 0.0))" instead of "Container(XY(0.0,0.0))"
  assert(xy.isInstanceOf[XY]) // fails
}

This happens only if the Vector2f is used as import Abstract.Link.Vector2f. Once you change it to Concrete.Vector2f it works fine.

@nbauernfeind
Copy link
Member

nbauernfeind commented Jun 29, 2018

I'm not quite sure how this is supposed to work.

For example, the compiler doesn't even know what type the imported Vector2f is:

    println(manifest[Vector2f])

Yields the errors:

Error:(41, 21) No Manifest available for Abstract.Link.Vector2f.
    println(manifest[Vector2f])

It knows what the type is supposed to be if your link doesn't cast to the super:

object Abstract {
  val Link = Concrete
}

Or

object Abstract {
  val Link: Concrete.type = Concrete
}

The only way that the compiler is figuring out how to construct an XY in val input = Container(Vector2f(0,0)) is because of the companion object that you've fabricated to get around the fact that the type is unknown in the abstract class.

I think you're going to want to approach this problem from another angle. Is this something you're still trying to work on?

OndrejSpanel added a commit to OndrejSpanel/JacksonTypeAlias that referenced this issue Jul 30, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants