Search code examples
jsonscalajacksondeserializationjackson-modules

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?


Solution

  • 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