SomeStranger314
SomeStranger314

Reputation: 387

JsValue filter out null values

I am trying to figure out how to avoid null values. My problem is, that I am querying an API and it returns a null value.

Here's an example:

import play.api.libs.json._

case class InnerExample(value: String)

object InnerExample {
def fromJson(json: JsValue) = InnerExample(
    value = (json \ "value")as[String]
}

case class Example(innerValue: Option[InnerExample])

object Example {
def fromJson(json: JsValue) = Example(
    optionalValue = (json \ "innerValue").asOpt[String].map(InnerExample.apply)
    )
}

The problem I am having is that asOpt transforms innerValue not to a None, but to a Some(null). I understand why and it makes a lot of sense. But I need to figure out a way to deal with it. Something more elegant than matching for Some(null). I am very grateful for any ideas.

Upvotes: 2

Views: 956

Answers (2)

SomeStranger314
SomeStranger314

Reputation: 387

Thanks to the answer from @Mario Galic, I went back to my code and opened up the documentation of JSLookups, which is what I get back when I use method \ of a JsValue. Turns out it does have a way to deal with null-values. It is done like this:

optionalValue = (json \ "innerValue").validateOpt[String].get.map(InnerExample.apply)

I think Mario's way is cleaner and should be recommended, but in my case it would means rewrite 10 case classes and my way is faster in modifying my existing code. Still, that is the reason why I will mark Mario's answer as accepted answer.

Upvotes: 1

Mario Galic
Mario Galic

Reputation: 48420

Consider readNullable. Here is working example:

import play.api.libs.json._

case class InnerExample(value: String)
case class Example(innerValue: Option[InnerExample])

object InnerExample {
  implicit val format = Json.format[InnerExample]
}

object Example {
  implicit val jsonread: Reads[Example] =
    (JsPath \ "innerValue").readNullable[InnerExample].map(Example.apply)
}

object NullableJson extends App {
  val jsonSomeStr = """{ "innerValue": { "value": "woohoo" } }"""
  val jsonSome = Json.parse(jsonSomeStr).as[Example] 
  println(jsonSome) // Example(Some(InnerExample(woohoo)))

  val jsonNullStr = """{ "innerValue": null }"""
  val jsonNull = Json.parse(jsonNullStr).as[Example]
  println(jsonNull) // Example(None)
}

Upvotes: 3

Related Questions