Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Option.apply throw NPEs for boxed primitives?

Tags:

scala

For example, the following code will throw an NPE:

val badData = null: java.lang.Long
val boom: Option[Long] = Option(badData)
java.lang.NullPointerException
  at scala.Predef$.Long2long(Predef.scala:358)
  ... 33 elided

This makes it difficult to work with Java APIs that return boxed primitives.

Note that in this silly example it's possible to just remove the type declaration from boom and the code will run without error, but in a more realistic example that may not be possible/easy. For example:

MyCaseClass(record getValue m.ID, Option(record getValue m.USER))

where record is pulling data from an external source.

like image 949
Ian Phillips Avatar asked Feb 10 '23 23:02

Ian Phillips


1 Answers

The issue is that on your second line boom is declared as a Scala Long therefore an implicit typecast takes place from java.lang.Long to Long, hence the NPE.

Just make sure you are using the correct Java Long or Scala Long types and that the implicit type conversion won't be invoked. So MyCaseClass should have Option[java.lang.Long] as its type. If you would like to work around this you can just explicitly type it before calling the Option.apply and then map it to the correct Scala type:

MyCaseClass(Option(badData: java.lang.Long).map(_.toLong))

Here's my REPL code:

scala> val badData = null: java.lang.Long
badData: Long = null

scala> val boom: Option[Long] = Option(badData)
java.lang.NullPointerException
  at scala.Predef$.Long2long(Predef.scala:358)
  ... 33 elided

scala> val boom: Option[java.lang.Long] = Option(badData)
boom: Option[Long] = None

scala> case class MyCaseClass(l: Option[Long])
defined class MyCaseClass

scala> MyCaseClass(Option(badData: java.lang.Long).map(_.toLong))
res3: MyCaseClass = MyCaseClass(None)
like image 91
Akos Krivachy Avatar answered Feb 16 '23 03:02

Akos Krivachy