Lorenzo Tassone
Lorenzo Tassone

Reputation: 383

Scala loop list of object


I have a list of JsObject like:

[{
  "a":"test1",
  "b": 2,
  "c": 5,
  "errors": "Error example"
}]

I would like to get something like this a:List[Option[String]], b: List[Option[Int]] and so on. I need an option since not all the fields are alway present.
My code is:

jsObjList.map(js => {
  val a = (js \ "a").asOpt[String]
  val b = (js \ "b").asOpt[Int]
  val c = (js \ "c").asOpt[Int]
  val er= (js \ "errors").asOpt[String]
  (a, b, er)
})

I read about unzip and unzip3 but I haven't found a generic function.

P.S. I am using Scala Play for the json parsing


Thanks for your help!

Upvotes: 0

Views: 474

Answers (2)

Nagarjuna Pamu
Nagarjuna Pamu

Reputation: 14825

Class to extract values from raw JSON.

case class Foo(a: Option[String], b: Option[Int], c: Option[Int],errors: Option[String])

object Foo {
  // Automatically generate json reader and writer for the class Foo
  implicit val format = Json.format[Foo]
}

Keeping the implicit value in companion object of Foo will make the Scala to pick up the implicit when required automatically.

Code to parse JSON into list of case class instances

 payload.validate[List[Foo]]

Use validateOpt in case you expect any parse error

payload.validateOpt[List[Foo]]

Scala REPL

scala> :paste
// Entering paste mode (ctrl-D to finish)


val str = """
[{
  "a":"test1",
  "b": 2,
  "c": 5,
  "errors": "Error example"
}]
"""

// Exiting paste mode, now interpreting.

str: String =
"
[{
  "a":"test1",
  "b": 2,
  "c": 5,
  "errors": "Error example"
}]
"

scala> val payload = Json.parse(str)
payload: play.api.libs.json.JsValue = [{"a":"test1","b":2,"c":5,"errors":"Error example"}]

scala> case class Foo(a: Option[String], b: Option[Int], c: Option[Int],errors: Option[String])
defined class Foo

scala> implicit val format = Json.format[Foo]
format: play.api.libs.json.OFormat[Foo] = play.api.libs.json.OFormat$$anon$1@53a0b0a3

scala> payload.validate[List[Foo]]
res5: play.api.libs.json.JsResult[List[Foo]] = JsSuccess(List(Foo(Some(test1),Some(2),Some(5),Some(Error example))),)

Upvotes: 1

James Whiteley
James Whiteley

Reputation: 3474

You can parse JSON as a Scala case class with a companion object containing a special val called implicit val format = Json.format[*your class*].

Here's an example similar to yours:

import play.api.libs.json.Json

val body =
  """{
    |  "a":"my string",
    |  "b": 1,
    |  "c": 2
    |}
  """.stripMargin

val body2 =
  """{
    |  "a":"my string",
    |  "c": 5
    |}
  """.stripMargin

case class MyClass(a: Option[String], b: Option[Int], c: Option[Int])

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

Using this, calling Json.parse(body).as[MyClass] gives:

res0: MyClass = MyClass(Some(my string),Some(2),Some(5))

Calling this Json.parse function with missing fields (assuming they are optional), such as Json.parse(body2).as[MyClass] gives:

res1: MyClass = MyClass(Some(my string),None,Some(5))

If one of the missing fields is not Optional, this parse will not work.

Upvotes: 0

Related Questions