anli
anli

Reputation: 377

jackson-module-scala: how to read subtype?

With this jackson-module-scala wrapper

object Json {
  private val ma = new ObjectMapper with ScalaObjectMapper
  ma.registerModule(DefaultScalaModule)
  ma.setSerializationInclusion(Include.NON_NULL)

  def jRead[T: Manifest](value: String): T = ma.readValue[T](value)
  def jWrite(value: Any) = ma.writer.writeValueAsString(value)
  def jNode(value: String) = ma.readTree(value)
}

I try to read subtype (it is just simplified use case without real work):

object TestJTrait extends App {
  trait T1
  object TestJ { def apply[X <: T1: Manifest](s: String): X = jRead[X](s) }
  case class C1(i: Int) extends T1
  TestJ(jWrite(C1(42)))
}

But this attempt results in the error:

Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Can not instantiate abstract type [simple type, class scala.runtime.Nothing$] (need to add/enable type information?)
 at [Source: {"i":42}; line: 1, column: 2]
    at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)
    at com.fasterxml.jackson.databind.deser.std.ThrowableDeserializer.deserializeFromObject(ThrowableDeserializer.java:73)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:124)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3051)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2160)
    at com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper$class.readValue(ScalaObjectMapper.scala:180)

Can anybody, please, suggest a workaround to get the intended behaveur?

Upvotes: 1

Views: 848

Answers (2)

Alexey Romanov
Alexey Romanov

Reputation: 170735

If you also have case class C2(i: Int) extends T1, how could it choose between reading C1 or C2? And if you don't, how could it know that you don't? After all, C2 could be anywhere in your program, perhaps in a class which hasn't been loaded yet (and so could C1!). Manifest in [X <: T1: Manifest] won't help either, since the type argument can't be inferred.

Upvotes: 1

Akhil
Akhil

Reputation: 558

Since T1 is a trait (abstract type) when deserializing it will try to create an instance of T1 it has no information about C1. You need to hint it.

TestJ[C1](jWrite(C1(42)) should help

Upvotes: 1

Related Questions