FasterXML / jackson-module-scala

Add-on module for Jackson (https://github.com/FasterXML/jackson) to support Scala-specific datatypes
Apache License 2.0
502 stars 142 forks source link

Decode into Scala Option[Long] populated as Java Integer #106

Closed uthornbl closed 11 years ago

uthornbl commented 11 years ago

When decoding a string into e.g. a case class with attributes of type Option[Long] it seems to work (no errors). However, when I later try to access the field and assign it to a Long val a cast error is thrown revealing that a Java Integer has been stored instead of a Long: ClassCastException: java.lang.Integer cannot be cast to java.lang.Long. Possible work-arounds are a) wrapping the Option[Long] making it a Long member of a case class and then use the case class as an Option or b) Use a Long and consider the value 0 as absence of input (this assumes you don't expect 0s from the source...) or c) Do the casting yourself when you access the field, e.g. myField.get.toString.toLong. Could the library be made to handle the decode properly?

christophercurrie commented 11 years ago

This is explained in the FAQ:

The Scala module has informed Jackson that Option is effectively a container type, but it relies on Java reflection to determined the contained type, and comes up with Object. Jackson has rules for dealing with this situation, which dictate that the dynamic type of Object values should be the closest natural Java type for the value: java.lang.String for strings, java.lang.Integer, java.lang.Long, or java.math.BigInteger for whole numbers, depending on what size the number fits into

The workaround for now is to use @JsonDeserialize(contentAs = classOf[java.lang.Long]) to tell Jackson to widen small integers to longs.

Resolving in favor of #104 which tracks the root cause of this issue.

StefanGheorghiu commented 10 years ago

You should use Scala reflection to extract the correct type parameter of Option. I succeeded to do it in my extension to Spring conversion service. If you need my help, I'll provide a clue.

christophercurrie commented 10 years ago

In an ideal world, this would be the way I would do it. However, Scala reflection in 2.10 has a bug that I was unable to work around when I first looked at it. #44 had the relevant changes, and I had integrated them into a branch, but at the time of 2.10.0-RC2, the tests were crashing.

The relevant bug is SI-6548, which is fixed, but due to binary compatibility restrictions cannot be released until Scala 2.11. Thus reflection is useless to me in 2.10.

Even if Scala reflection worked perfectly in 2.10, there's still the problem of 2.9 support which I have not yet decided to abandon. The current road map is to implement an approach based on parsing @ScalaSignature, which is pending development of a library to do that, which doesn't depend on the scala compiler itself (as most scalap-based signature parsing tools do). That work is still in progress.

StefanGheorghiu commented 10 years ago

Unfortunately, there are lots of issues in 2.10 reflection. I encountered another one causing sporadic exceptions on multi-threaded calls to the reflection API. The only workaround was to synchronize all such calls globally.