Reputation: 20581
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
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
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