1
votes

I'm new to Jackson. I am encountering the following error when using Jackson to deserialize a JSON string if I don't explicitly specify a class type during deserialization:

com.fasterxml.jackson.databind.JsonMappingException: Can not instantiate abstract type [simple type, class scala.runtime.Nothing$] (need to add/enable type information?)

Is there a way to serialize / deserialize JSON in Jackson without having to specify the class type?

Here is my test code:

import java.lang.reflect.{Type, ParameterizedType}
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.`type`.TypeReference;
import org.junit._
import org.junit.Assert._

case class Person (name:String)
case class Address (city:String, state:String)

class JSONTest {

  @Test
  def jsonTest () = {

    val p = new Person ("Bob")

    val json = JacksonWrapper.serialize(p)
    println ("json= " + json)
    val obj = JacksonWrapper.deserialize[Person](json)
    println ("obj = " + obj)

    // fails since class type isn't explictly specified.  
    // is there a way to do it so that class type is automatically determined?
    val obj2 = JacksonWrapper.deserialize(json)
    println ("obj= " + obj2)


  }



}

//http://stackoverflow.com/questions/12591457/scala-2-10-json-serialization-and-deserialization
object JacksonWrapper {
  val mapper = new ObjectMapper()
  mapper.registerModule(DefaultScalaModule)

  def serialize(value: Any): String = {
    import java.io.StringWriter
    val writer = new StringWriter()
    mapper.writeValue(writer, value)
    writer.toString
  }

  def deserialize[T: Manifest](value: String) : T =
    mapper.readValue(value, typeReference[T])

  private [this] def typeReference[T: Manifest] = new TypeReference[T] {
    override def getType = typeFromManifest(manifest[T])
  }

  private [this] def typeFromManifest(m: Manifest[_]): Type = {
    if (m.typeArguments.isEmpty) { m.erasure }
    else new ParameterizedType {
      def getRawType = m.erasure
      def getActualTypeArguments = m.typeArguments.map(typeFromManifest).toArray
      def getOwnerType = null
    }
  }
}
1

1 Answers

1
votes

You have to provide the type information somehow. Jackson serializes to JSON only your object's fields, it doesn't store additional information about the type anywhere, so for your Person class, the JSON probably looks like this: { "name": "Bob"}. Without you providing the information that you want to deserialize as an instance of Person, Jackson can't known the type. You could have another class with the field name as well, and JSON doesn't say which one you need. That's why you need to provide the type when deserializing - in Java by passing an argument of type Class and in Scala by providing the type parameter to ObjectMapper and friends.