FasterXML / jackson-module-scala

Add-on module for Jackson (https://github.com/FasterXML/jackson) to support Scala-specific datatypes

Home Page:http://fasterxml.github.io/jackson-module-scala/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Case Classes with Option[Long] parameters don't deserialize properly

kscaldef opened this issue · comments

It seems that for small numbers, an Option[Long] in a case class actually gets deserialized with a runtime type of int. This can then manifest in a couple ways. Maps using these values as keys may not behave as expected, and conversions to Java Longs will throw a ClassCastException:

[info]   java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long
[info]   at scala.runtime.BoxesRunTime.unboxToLong(Unknown Source)

This only seems to affect case classes. Option[Long] by itself seems to behave correctly.

This uncovers one of the dirtier parts of Scala. The JVM doesn't support using an intrinsic like long as a type parameter, and Long is just long in the Scala type system. At one point I think that they mapped it to the boxed types in the type parameter but that ended up being a source of bugs, so they changed to Object.

For 2.2, I've added patches to databind to support using @JsonDeserialize as a workaround:

class OptionLongHolder
{
  @JsonDeserialize(contentAs=classOf[java.lang.Long])
  var optLong: Option[Long]
}

This works, as it forces Jackson to use Long for deserialization rather than the narrowest natural integer.

We're currently tied to jackson 2.1.x. Is it somehow possible to get this backported?

I'll look into it. AFAIK, core Jackson doesn't plan on any further maintenance on 2.1.x, but I'll see what I can do about an interim release.

Ok, thanx!

Hello,

Just wanted to thank you for the fix in 2.2. Got a bit stressed when I noticed that conversion bug, so I was relieved to see that it's solved using the @JsonDeserialize(contentAs=classOf[java.lang.Long]) annotation.

What is the workaround if your case class is generated for you? I don't have an access to apply attribute.

@christophercurrie is it possible to create an optional module that uses what finatra has to work around this? It looks like they use the scala signature parsing https://github.com/twitter/finatra/tree/develop/jackson/src/main/scala/com/twitter/finatra/json/internal/caseclass/jackson

Having to annotate works fine, but its problematic when you are trying to distribute a model class (for example) which now pulls in all of jackson databind. Had the annotation been in jackson-annotations it would be less problematic, but leaking a dependency like that really sucks.

I'd be really open to having a separate module (if we don't want to include that in the main one) that provided for option[long] parsing via signature parsing in the interim, until the deprecation comes around for 2.10>