0
votes

For example my json data is like:

[{
  "name": "Foo",
  "verified": {"email": true, "mobile": false}
}, {
  "name": "Bar",
  "verified": {"email": false, "mobile": false}
}]

With json4s I can get a JArray, before extracting to a list of User (case class) I want to manipulate the JArray - I want to flatten the verified field so a user would be like:

case class (name: String, emailVerified: Boolean, mobileVerified: Boolean)

How can I do that?

1

1 Answers

2
votes

You can transform an existing AST like this:

import org.json4s._
import org.json4s.jackson.JsonMethods._
import org.json4s.JsonDSL._

object test extends App {

  val json = """[{
             |  "name": "Foo",
             |  "verified": {"email": true, "mobile": false}
             |}, {
             |  "name": "Bar",
             |  "verified": {"email": false, "mobile": false}
             |}]""".stripMargin

  def t(js: JValue): JValue = for {
    JString(name) <- js \ "name"
    JBool(ver1) <- js \ "verified" \ "email"
    JBool(ver2) <- js \ "verified" \ "mobile"
  } yield ("name" -> name) ~ ("emailVerified" -> ver1) ~ ("mobileVerified" -> ver2)

  for {
    JArray(xs) <- parse(json)
  } yield JArray(xs map t)

}

Another option is write a custom serializer for it:

import org.json4s._
import org.json4s.jackson.JsonMethods._
import org.json4s.JsonDSL._

object userTest extends App {

  val json = """{
               |  "name": "Bar",
               |  "verified": {"email": false, "mobile": false}
               |}""".stripMargin

  case class UserFoo(name: String, emailVerified: Boolean, mobileVerified: Boolean)

  class UserFooSerializer extends CustomSerializer[UserFoo](formats => ( {
    case js: JValue =>
      val u = for {
        JString(name) <- js \ "name"
        JBool(userVerified) <- js \ "verified" \ "email"
        JBool(mobileVerified) <- js \ "verified" \ "mobile"
      } yield UserFoo(name, userVerified, mobileVerified)
      u.head
  }, Map.empty))


  implicit val formats = DefaultFormats + new UserFooSerializer

  parse(json).extractOpt[UserFoo] map {
    user =>
      println(user)
      // UserFoo(Bar,false,false)

      println(pretty(Extraction.decompose(user)))
      // {
      //   "name" : "Bar",
      //   "emailVerified" : false,
      //   "mobileVerified" : false
      // }
  }

}