播放 Json 读取嵌套的通用序列化 Json

Play Json Reads nested generic serialized Json

考虑以下 JSON

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

我想为这种序列化Json

定义一个通用的读取Reads[Outer[T]]
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]] = ???
}

我怎样才能实现我的目标?我试图为字段 "outer.a" flatMap a string-reads 但卡住了,因为我无法从经过验证的 JSON

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

您只需要在 validate[T] 调用后在 Outer.reads 构造中添加 map

请查看下一个代码示例:

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]])
  }
}

在我的案例中产生了下一个结果:

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

希望对您有所帮助!