Search code examples
scalanullimplicit-conversionimplicit

How to implicitly wrap a value that can be null or an array into an Scala Option


I have this Java class in a Jar file included as a dependency of an Scala program (like the Axis jar):

class MyClass {
    private String[] someStrings;
    public String[] getSomeStrings() { return someStrings; }
}

In my Scala program I have a Java API that return an instance of MyClass instance of MyClass to my program in Scala:

val myInstance = JavaAPI.getInstanceOfMyClass()

Then I try to use the someStrings array in my Scala program but it's null (let say that it wasn't properly initialized)

for(str <- myInstance.getSomeStrings()) ...

So this throws a NullPointerException.

I've found that in order to use it in the for comprehension I can wrap it into an Option so that it handles the NPE properly.

for(str <- Option[Array[String]](myInstance.getSomeStrings).getOrElse(Array[String]())

But that doesn't look OK to me.

Is there a way to create like an implicit method that takes that value even if it's null and wrap it into the Option, like:

implicit def wrapNull(a: Null): Option[Nothing] = None
implicit def wrapArray(a: Array[String]): Option[Array[String]] = Some(a)

So that when I do:

for(str <- myInstance.getSomeStrings())

I don't get the NPE


Solution

  • I don't think your version with getOrElse is that bad (you can make it a little shorter by removing the [Array[String]] after Option, since that can be inferred). If you want something even more concise, the following works:

    for (str <- Option(myInstance.getSomeStrings).flatten) ...
    

    You could also use the fact that Option has a foreach:

    for {
      strings <- Option(myInstance.getSomeStrings)
      str <- strings
    } ...
    

    Note that you can't use yield here, for the reason that drexin highlights in a comment below.

    Or you could pimp MyClass:

    implicit def withNullWrapper(c: MyClass) = new {
      def getSomeStringsOrNot() = Option(c.getSomeStrings).getOrElse(Array[String]())
    }
    
    for (str <- myInstance.getSomeStringsOrNot) ...