Preface
I'd like to deserialize json to the following class
case class Target(
a: Option[Long],
b: String
)
with the following code:
val mapper = new ObjectMapper()
.registerModule(DefaultScalaModule)
val req =
"""{
| "a": 123,
| "b": "xyz"
|}
""".stripMargin
val res = mapper.readValue(req, classOf[Target])
but due to a bug in jackson (as explained in FAQ),
the following code will fail:
println(res.a.map(_ + 1))
with error:
java.lang.Integer cannot be cast to java.lang.Long
creating the following mixin solves that bug, and the code work as expected:
class Mixin(
@JsonDeserialize(contentAs = classOf[Long]) a: Option[Long],
b: String
)
val mapper = new ObjectMapper()
.registerModule(DefaultScalaModule)
.addMixIn(classOf[Target], classOf[Mixin])
val res = mapper.readValue(req, classOf[Target])
println(res.a.map(_ + 1))
Problem
In my case Target
class contains a lot of fields, and only one of them needs an annotation.
therefore, I'd like to create the Mixin
with only a single argument:
class Mixin(
@JsonDeserialize(contentAs = classOf[Long]) a: Option[Long]
)
But when defining Mixin
like this, the annotation seems to not be applied, and this code fails again:
println(res.a.map(_ + 1))
is there a way to make it work?
Full code to recreate the problem:
case class Target(
a: Option[Long],
b: String
)
class Mixin(
@JsonDeserialize(contentAs = classOf[Long]) a: Option[Long]
// , b: String //<--- uncommenting this line will fix the code
)
val mapper = new ObjectMapper()
.registerModule(DefaultScalaModule)
.addMixIn(classOf[Target], classOf[Mixin])
val req =
"""{
| "a": 123,
| "b": "xyz"
|}
""".stripMargin
val res = mapper.readValue(req, classOf[Target])
println(res.a.map(_ + 1))
The problem could be that your mixin doesn't actually declare any fields - only constructor. And constructor gets overridden by your case class. So what you can do is model your Mixin as a trait with the annotated getter: