I am trying to serialise GeneralResponse
:
case class GeneralResponse[T](succeeded: Boolean, payload: Option[T])
and the payload is GroupsForUserResult
:
case class GroupsForUserResult(groups: Seq[UUID]).
I am using mapper.readValue(response.body, classOf[GeneralResponse[GroupsForUserResult]])
but unfortunately the payload is serialised as a Map
and not as the desired case class (GroupForUserResult
).
Yes, that is safe and recommended.
ObjectMapper is the main actor class of Jackson library. ObjectMapper class ObjectMapper provides functionality for reading and writing JSON, either to and from basic POJOs (Plain Old Java Objects), or to and from a general-purpose JSON Tree Model (JsonNode), as well as related functionality for performing conversions.
Mapper instances are fully thread-safe provided that ALL configuration of the instance occurs before ANY read or write calls.
Class TypeReference<T> This generic abstract class is used for obtaining full generics type information by sub-classing; it must be converted to ResolvedType implementation (implemented by JavaType from "databind" bundle) to be used.
Because of Java Erasure - Jackson can't know at runtime about the generic type T from the line -
mapper.readValue(response.body, classOf[GeneralResponse[GroupsForUserResult]])
A solution to this problem will be
import com.fasterxml.jackson.core.`type`.TypeReference
mapper.readValue(json, new TypeReference[GeneralResponse[GroupsForUserResult]] {})
This way you provide an instance of TypeReference
with all the needed Type information.
The accepted answer is close enough but you also have to provide the Type Parameter to .readValue
method,
Working example with test,
import com.fasterxml.jackson.core.`type`.TypeReference
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import org.scalatest.{FunSuite, Matchers}
case class Customer[T](name: String, address: String, metadata: T)
case class Privileged(desc: String)
class ObjectMapperSpecs extends FunSuite with Matchers {
test("deserialises to case class") {
val objectMapper = new ObjectMapper()
.registerModule(DefaultScalaModule)
val value1 = new TypeReference[Customer[Privileged]] {}
val response = objectMapper.readValue[Customer[Privileged]](
"""{
"name": "prayagupd",
"address": "myaddress",
"metadata": { "desc" : "some description" }
}
""".stripMargin, new TypeReference[Customer[Privileged]] {})
response.metadata.getClass shouldBe classOf[Privileged]
response.metadata.desc shouldBe "some description"
}
}
The signature of com.fasterxml.jackson.databind.ObjectMapper#readValue
,
public <T> T readValue(String content, TypeReference valueTypeRef)
throws IOException, JsonParseException, JsonMappingException
{
return (T) _readMapAndClose(_jsonFactory.createParser(content), _typeFactory.constructType(valueTypeRef));
}
If you don't provide the type parameter, it will blow up with error Customer cannot be cast to scala.runtime.Nothing$
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With