3

My sample json is either with a country object Json sample 1

  "@version": "1.0",
    "country": {
        "@country": "US",
        "day": {
            "@date": "2016-02-15",
            "@value": "1"
        }
    }

or with country array: Json sample 2

"@version": "1.0",
    "country": [{
        "@country": "US",
        "day": {
            "@date": "2016-02-15",
            "@value": "1"
        }
    }, {
        "@country": "UK",
        "day": {
            "@date": "2016-02-15",
            "@value": "5"
        }]
    }

To read the json

 implicit val dayJsonReads: Reads[DayJson] = (
      (JsPath \ "@date").read[DateTime](dateReads) and
        ((JsPath \ "@value").read[Int] orElse (JsPath \ "@value").read[String].map(_.toInt))
      )(DayJson.apply _)

    implicit val countryJsonReads: Reads[CountryJson] = (
      (JsPath \ "@country").read[String] and
        (JsPath \ "day").read[DayJson]
      )(CountryJson.apply _)

 implicit val newUserJsonReads: Reads[NewUserJson] = (
      (JsPath \ "@version").read[String] and
        (JsPath \ "country").readNullable[Seq[CountryJson]] 
      )(NewUserJsonParent.apply _)

The above code reads sample json 2 however fails for sample json 1. Is it possible to use readNullable to read either JS Value or JS Object or can we convert it from JS Value to JS Object. Thank you.

2 Answers 2

4

You can do something like this:

object NewUserJson{
implicit val newUserJsonReads: Reads[NewUserJson] = (
  (JsPath \ "@version").read[String] and
    (JsPath \ "country").read[JsValue].map{
      case arr: JsArray => arr.as[Seq[CountryJson]]
      case obj: JsObject => Seq(obj.as[CountryJson])
    }
  )(NewUserJson.apply _)
}

This should work for this case class:

case class NewUserJson(`@version`: String, country: Seq[CountryJson])

But I don't like it, can't you just use the same structure, and when you have only one country just send a list that hold only one country, instead of object?

Sign up to request clarification or add additional context in comments.

6 Comments

Thank you for your reply. Yes, I would like to convert the single object to a list. Can I write it like this? object NewUserJson{ implicit val newUserJsonReads: Reads[NewUserJson] = ( (JsPath \ "@version").read[String] and (JsPath \ "country").read[JsValue].map{ case arr: JsArray => arr.as[Seq[CountryJson]] case obj: JsObject => obj.as[Seq[CountryJson]] } )(NewUserJson.apply _) }
For the above, I keep getting "Application does not take parameters error"
My answer did not work for you? you cannot read the object as Seq while it's a single object.
It did not work. Should I change the case class type too?
I updated the answer, the case class should be : case class NewUserJson(@version: String, country: Seq[CountryJson]) If it doesn't work for you I can share the full example, and the test that passed for both jsons. Tell me if it worked for you or not.
|
1

Working on Tomer's solution, below is a working sample. It would be nice if I can make it more compact.

Case class

case class NewUserJson(version: String, country: Option[Seq[CountryJson]])

Json parsing object

 object NewUserJson{
    implicit val newUserJsonReads: Reads[NewUserJson] = (
      (JsPath \ "@version").read[String] and
        (JsPath \ "country").readNullable[JsValue].map {
          arr => {
            if (!arr.isEmpty){
              arr.get match {
                case arr: JsArray => Option(arr.as[Seq[CountryJson]])
                case arr: JsObject => Option(Seq(arr.as[CountryJson]))
              }
            }else {
              None
            }
          }
        }
      )(NewUserJson.apply _)
    }

1 Comment

Tomer wrote write solution. If you want use nullable, you can modify his code to "readNullable[JsValue].map{_.map{case arr: JsArray => ...}}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.