Итак, как уже было предложено в разделе комментариев, вы можете перейти к библиотеке circe вместо платформы Lift, потому что это гораздо более современное и широко используемое решение.
Что вы нужно сделать - объявить структуры, например case class
, которые представляют ваш json. Это не рекомендуемый подход, работать над необработанным JSON - эмпирическим правилом - анализировать его в какую-то значимую структуру и затем работать с ней.
Наряду с декларацией структуры вы также Encoder
и Decoder
скажем, в «нестандартных» случаях - например, Boolean
, что составляет String
в случае поля organic
.
В вашем случае код может выглядеть следующим образом:
object App {
def main(args: Array[String]): Unit = {
import io.circe._, io.circe.generic.semiauto._, io.circe.generic.auto._, io.circe.parser._
/**
* General purpose response wrapper. Entries type might differ, as I can suppose, that's why it is generic.
* 'errorMessages' - since it is empty array in example, I can only guess about exact type. For sake of example
* let's say it is strings. And same for 'error' field.
*/
case class Response[E](requestId: String, error: Option[String], errorMessages: List[String], entries: List[E])
object Response {
implicit def decoder[E](implicit d: Decoder[E]): Decoder[Response[E]] = deriveDecoder[Response[E]]
implicit def encoder[E](implicit e: Encoder[E]): Encoder[Response[E]] = deriveEncoder[Response[E]]
}
case class Product(modelId: String, sku: String, store: String, ttlInSeconds: Int, metadata: ProductMetadata)
case class ProductMetadata(manufactured_date: ZonedDateTime, organic: Boolean)
object ProductMetadata {
// Boolean codec required - because `organic` is a string in JSON, which has boolean type
implicit val booleanDecoder: Decoder[Boolean] = Decoder[String].emapTry(value => Try(value.toBoolean))
implicit val booleanEncoder: Encoder[Boolean] = Encoder[String].contramap(_.toString)
implicit val decoder: Decoder[ProductMetadata] = deriveDecoder[ProductMetadata]
implicit def encoder: Encoder[ProductMetadata] = deriveEncoder[ProductMetadata]
}
val json =
s"""
|{
| "requestId":"91ee60d5f1b45e#316",
| "error":null,
| "errorMessages":[
|
| ],
| "entries":[
| {
| "modelId":"RT001",
| "sku":"SKU-ASC001",
| "store":"livingstone",
| "ttlInSeconds":8000,
| "metadata":{
| "manufactured_date":"2019-01-22T01:25Z",
| "organic":"true"
| }
| },
| {
| "modelId":"RT002",
| "sku":"SKU-ASC002",
| "store":"livingstone",
| "ttlInSeconds":8000,
| "metadata":{
| "manufactured_date":"2019-10-03T01:25Z",
| "organic":"false"
| }
| }
| ]
|}
|""".stripMargin
val parseResult: Either[Error, List[String]] =
for {
parsedJson <- parse(json)
response <- parsedJson.as[Response[Product]]
} yield {
response.entries.collect {
case Product(modelId, _, "livingstone", _, ProductMetadata(_, true)) => modelId
}
}
println(parseResult)
}
который даст следующий результат
Right(List(RT001))
Надеюсь, это поможет!