Kris
Kris

Reputation: 45

Parse JSON object into list of objects

I'm trying to use circe to decode a JSON object into a list of objects. I only want to use some of the fields of the JSON response to create the object, so I feel like I have to create a custom decoder.

The class I want to make a sequence of is defined as follows:

case class Review(Id: String, ProductId: String, Rating: Int)

I tried creating a custom decoder like this:

implicit val reviewDecoder: Decoder[Review] = Decoder.instance { c =>

  val resultsC = c.downField("Results")

  for {
    id <- resultsC.downArray.get[String]("Id")
    productId <- resultsC.downArray.get[String]("ProductId")
    rating <- resultsC.downArray.get[Int]("Rating")
  } yield Review(id, productId, rating)
}

reviewDecoder.decodeJson(json) seems to result in only doing the first result and not all of them.

I have a JSON response like this:

 {
   "Limit":2,
   "Offset":0,
   "TotalResults":31,
   "Locale":"en_US", 
   "Results":
   [
      {"Id":"14518388",
       "CID":"21a9436b",
       "ProductId":"Product11", 
       "AuthorId":"jcknwekjcnwjk",
       "Rating":3
      },
      {"Id":"14518035",
       "CID":"8d67b6f5",
       "ProductId":"Product11",
       "AuthorId":"fnkjwernfk",
       "Rating":3
      }
   ],
   "Includes":{},
   "HasErrors":false,
   "Errors":[]}

I want to be able to parse this JSON object using circe to create a Seq[Review], but I'm stumped how.

****Edit** Luis' answer does answer this question but say I have a more complicated class I want to create a sequence of:

case class User(id: Int)

case class Review(user: User, ProductId: String, Rating: Int)

How would I be able to create a sequence of Reviews in this case?

Upvotes: 1

Views: 1055

Answers (1)

I would just use the cursor to getting the Array and then use the generic decoder.

The following code was tested on ammonite, where json is a string containing your sample input.

import $ivy.`io.circe::circe-core:0.11.1`
import $ivy.`io.circe::circe-generic:0.11.1`
import $ivy.`io.circe::circe-parser:0.11.1`

import io.circe.{Decoder, Jsom}
import io.circe.parser.parse

final case class Review(Id: String, ProductId: String, Rating: Int)
implicit val reviewDecoder: Decoder[Review] = io.circe.generic.semiauto.deriveDecoder

parse(json).getOrElse(Json.Null).hcursor.downField("Results").as[List[Review]]
// res: io.circe.Decoder.Result[List[Review]] = Right(List(Review("14518388", "Product11", 3), Review("14518035", "Product11", 3)))

Upvotes: 1

Related Questions