4

I'm writing a function to get an entry from a JSONObject. Since it is JSON the entry by the input name may or may not exist and so the function return an Option which will be None when the Try fails or if the value is NULL on success. The function fails to compile and errors about incorrect return type.

def tryGet[T](jsonObject: JSONObject, name: String): Option[T] = {
  Try(jsonObject.get(name))
    .map(x => if(JSONObject.NULL.equals(x)) None else x.asInstanceOf[T])
    .toOption
}

Error:

Expression of type Option[Any] doesn't conform to expected type Option[T]

Can someone tell me what I'm doing wrong here? Also, is this the idiomatic way to approach the problem?

Update:

Changing to the below works

def tryGet[T](jsonObject: JSONObject, name: String): Option[T] = {
    Try(jsonObject.get(name))
      .filter(!JSONObject.NULL.equals(_))
      .map(_.asInstanceOf[T])
      .toOption
}
broun
  • 2,483
  • 5
  • 40
  • 55

2 Answers2

4

The problem is with this line:

.map( x => if(x.equals(null)) None else x.asInstanceOf[T])
This has type `Option[Nothing]` ^         ^ This has type `T`

You have both an Option[Nothing] and a T in the if/else statement. The result type of if/else is the least upper-bound (the nearest common type) of the result type of if and the result type of else. In this case, they have nothing in common but Any. So the the result is Try[Any] which gets converted to Option[Any] by toOption.

If you really need to check for null, use filter instead.

def tryGet[T](jsonObject: JSONObject, name: String): Option[T] =
    Try(jsonObject.get(name))
        .map(_.asInstanceOf[T])
        .filter(_ != null)
        .toOption
Michael Zajac
  • 55,144
  • 7
  • 113
  • 138
0

I don't think you need the null check, and "None" and "T" are two possible result in the map, so the type will be mapped to Any instead of "T" in your code. Check this:

Try(jsonObject.get(name)).map( _.asInstanceOf[T]).toOption

Then you might need something like this:

val NullJson:Option[T] = None
Try(jsonObject.get(name)).map( x=>if(x.equals(null)) NullJson else Option(x.asInstanceOf[T])).toOption.flatten
Binzi Cao
  • 1,075
  • 5
  • 14
  • Yeah I tried it and it throws "Exception in thread "main" java.lang.ClassCastException: org.json.JSONObject$Null cannot be cast to java.lang.String" at runtime as it is trying to cast a null to String. – broun Sep 02 '15 at 01:41
  • 1
    @broun You should write which json library you are using. I think your json library is not returning `null`, instead it is returning non-null object `org.json.JSONObject$Null` – ymonad Sep 02 '15 at 01:57
  • yeah, just figured that it is returning a custom NULL type. I was checking java null instead – broun Sep 02 '15 at 02:04
  • Adding filter to the try does the trick. Thanks for the help. – broun Sep 02 '15 at 02:14