Play Json Считывает вложенные generi c serialized Json - PullRequest
2 голосов
/ 17 февраля 2020

Рассмотрим следующее JSON

{
    "a": "{\"b\": 12, \"c\": \"test\"}"
}

Я хотел бы определить обобщенные c чтения Reads[Outer[T]] для этого вида сериализованных Json

import play.api.libs.json.{Json, Reads, __}

final case class Outer[T](inner: T)
final case class SpecializedInner(b: Int, c: String)

object SpecializedInner {
   implicit val reads: Reads[SpecializedInner] = Json.reads[SpecializedInner]
}

object Outer {
   implicit def reads[T](implicit readsT: Reads[T]): Reads[Outer[T]] = ???
}

Как могу ли я достичь своей цели? Я попытался выполнить flatMap для чтения строк для поля "outer.a", но застрял, так как не могу произвести чтение [T] из проверенного JSON

object Outer {
  implicit def reads[T](implicit readsT: Reads[T]): Reads[Outer[T]] =
    (__ \ "a").read[String].flatMap(x => Json.parse(x).validate[T])
}

1 Ответ

2 голосов
/ 17 февраля 2020

Вам нужно просто добавить map внутри Outer.reads конструкции после validate[T] вызова.

Пожалуйста, посмотрите следующий код, например:

object App {

  final case class Outer[T](inner: T)

  object Outer {
    implicit def reads[T](implicit innerReads: Reads[T]): Reads[Outer[T]] = { json: JsValue =>
      json.validate[String].flatMap(string => Json.parse(string).validate[T].map(Outer.apply[T]))
    }
  }

  final case class Root[T](a: Outer[T])
  object Root {
    implicit def reads[T](implicit innerReads: Reads[T]): Reads[Root[T]] = Json.reads
  }

  final case class SpecializedInner(b: Int, c: String)

  object SpecializedInner {
    implicit val reads: Reads[SpecializedInner] = Json.reads
  }

  def main(args: Array[String]): Unit = {
    val rawJson  = "{\"a\": \"{\\\"b\\\": 12, \\\"c\\\": \\\"test\\\"}\"}"
    println(Json.parse(rawJson).validate[Root[SpecializedInner]])
  }
}

Который дал следующий результат в моем case:

JsSuccess(Root(Outer(SpecializedInner(12,test))),)

Надеюсь, это поможет!

...