WelcomeTo
WelcomeTo

Reputation: 20581

Parsing null values in JSON using json4s

I'm using json4s library in my project to manually parse JSON field by field (without automatic deserializing it to case classes).

For example I have following JSON:

{
  result: "OK",
  persons: [
    {name: "Alex"},
    {name: null}
  ] 
}

And the official guide suggest to use this approach to manually parse it:

for {
         JArray(persons) <- json / "persons"
         JObject(person) <- persons
         JField("name", JString(name)) <- person
       } yield Person(name) 

The problem is that this for-comprehension skips persons which has null names. I think this is because in for-comprehension I used JString(name), so it expects some String value, not a null.

Is there any way to solve this? I just want to iterate over array and visit every object (even if it has null instead some String)

Upvotes: 3

Views: 4153

Answers (2)

S.Karthik
S.Karthik

Reputation: 1389

This will do,

 val r:List[Person] = for {
    JArray(persons) <- JsonMethods.parse(json) \ "persons"
    JObject(person) <- persons
    //JField("name", JString(name)) <- person
   p = Person(person.head._2) //or Person(person.find(_._1=="name").map(_._2).getOrElse(null))
  } yield p

  println(r) //List(Person("Alex"), Person(null))

Upvotes: 0

Allen Chou
Allen Chou

Reputation: 1237

Yeah, you've already got the reason it can't work, you just have to change the pattern match like the following.

case class Person(name: String)
// the result is actually List[Option[Person]]
val result =
  for {
    JArray(persons) <- json \ "persons"
    JObject(person) <- persons
    // jv is JsonAST.JValue
    JField("name", jv) <- person
  } yield {
    // in case of match error so add _ here
    jv match {
      case JString(name) => Some(Person(name))
      case JNull => Some(Person(null))
      case _ => None
    }
  }

Actually, there is another simpler way following the Extracting values part in the documentation you mentioned.

case class Person(name: String)
import org.json4s.DefaultFormats
implicit val formats = DefaultFormats // Brings in default date formats etc
val result2 = (json \ "persons").extract[List[Person]]
// List(Person(Alex), Person(null))
println(result2)

Upvotes: 2

Related Questions