使用Play框架读取具有递归密封特征列表的JSON。

huangapple go评论71阅读模式
英文:

Use Play framework to read JSON with recursive list of sealed traits

问题

我已经有一些需要解析的JSON,而且我的项目已经在使用Play,所以这似乎是一个合适的起点。

给定以下定义:

sealed trait Thing
case class Foo(i: Int) extends Thing
case class Bar(s: String, t: List[Thing]) extends Thing

我希望这个JSON:

{
  "s": "doomy doomy doom",
  "t": [ 24, { "s": "doooom!", "t": [ 1, 2, 3 ] }, 42, 126 ]
}

转换成这个对象:

Bar("doomy doomy doom", List(Foo(24), Bar("doooom!", List(Foo(1), Foo(2), Foo(3))), Foo(42), Foo(126)))

有什么建议吗?

英文:

I've got some JSON that I need to parse, and my project already uses Play, so that seems like the right place to start.

Given these definitions:

sealed trait Thing
case class Foo(i: Int) extends Thing
case class Bar(s: String, t: List[Thing]) extends Thing

I would want this JSON:

{
  s: "doomy doomy doom",
  t: [ 24, { s: "doooom!", t: [ 1, 2, 3 ] }, 42, 126 ]
}

To become this object:

Bar("doomy doomy doom", List(Foo(24), Bar("doooom!", List(Foo(1), Foo(2), Foo(3))), Foo(42), Foo(126)))

Any suggestions?

答案1

得分: 2

以下是您要翻译的内容:

要补充 @dmytro-mitin 的答案,您可以在 Foo 中使用 Scala 的 value classPlay JSON 文档 包括用于值类的 Reads/Writes/Formats。然后,您可以在您的原始示例中使用 Int,而不是一个带有单个字段的对象。以下是一个使用值类的更新示例:

import play.api.libs.json._
import play.api.libs.functional.syntax._

sealed trait Thing extends Any

object Thing {
  implicit val thingReads: Reads[Thing] = Foo.fooReads.or[Thing](Bar.barReads.widen)

  implicit val thingWrites: Writes[Thing] = {
    case f: Foo => Foo.fooWrites.writes(f)
    case b: Bar => Bar.barWrites.writes(b)
  }
}

case class Foo(i: Int) extends AnyVal with Thing

object Foo {
  implicit val fooReads: Reads[Foo] = Json.valueReads[Foo]
  implicit val fooWrites: Writes[Foo] = Json.valueWrites[Foo]
}

case class Bar(s: String, t: List[Thing]) extends Thing

object Bar {
  implicit val barReads: Reads[Bar] = (
    (__ \ "s").read[String] and
      (__ \ "t").lazyRead(Reads.list[Thing](Thing.thingReads))
  )(Bar.apply _)

  implicit val barWrites: Writes[Bar] = (
    (__ \ "s").write[String] and
      (__ \ "t").lazyWrite(Writes.list[Thing](Thing.thingWrites))
  )(unlift(Bar.unapply))
}

val thing: Thing = Bar("doom", List(Foo(12), Bar("doom", List(Foo(1), Foo(2), Foo(3))))
val json = Json.toJson(thing)
val str = Json.stringify(json)
val thing1 = Json.parse(str).as[Thing]
thing1 == thing
英文:

To add to @dmytro-mitin answer, you can use Scala's value class for Foo. Play JSON documentation includes Reads/Writes/Formats for value classes. Then you can use Int instead of an object with single field in your original example. Here is an updated example with a value class:

import play.api.libs.json._
import play.api.libs.functional.syntax._

sealed trait Thing extends Any

object Thing {
  implicit val thingReads: Reads[Thing] = Foo.fooReads.or[Thing](Bar.barReads.widen)

  implicit val thingWrites: Writes[Thing] = {
    case f: Foo => Foo.fooWrites.writes(f)
    case b: Bar => Bar.barWrites.writes(b)
  }
}

case class Foo(i: Int) extends AnyVal with Thing

object Foo {
  implicit val fooReads: Reads[Foo] = Json.valueReads[Foo]
  implicit val fooWrites: Writes[Foo] = Json.valueWrites[Foo]
}

case class Bar(s: String, t: List[Thing]) extends Thing

object Bar {
  implicit val barReads: Reads[Bar] = (
    (__ \ "s").read[String] and
      (__ \ "t").lazyRead(Reads.list[Thing](Thing.thingReads))
  )(Bar.apply _)

  implicit val barWrites: Writes[Bar] = (
    (__ \ "s").write[String] and
      (__ \ "t").lazyWrite(Writes.list[Thing](Thing.thingWrites))
  )(unlift(Bar.unapply))
}

val thing: Thing = Bar("doom", List(Foo(12), Bar("doom", List(Foo(1), Foo(2), Foo(3)))))
val json = Json.toJson(thing)
val str = Json.stringify(json)
// {"s":"doom","t":[12,{"s":"doom","t":[1,2,3]}]}
val thing1 = Json.parse(str).as[Thing]
// Bar(doom,List(Foo(12), Bar(doom,List(Foo(1), Foo(2), Foo(3)))))
thing1 == thing // true

答案2

得分: 1

以下是您要翻译的内容:

尝试为该特质(无鉴别器)定义自定义编解码器,以及递归类型的懒编解码器。

import play.api.libs.json._
import play.api.libs.functional.syntax._

sealed trait Thing
object Thing {
  implicit val thingReads: Reads[Thing] = Foo.fooReads.or[Thing](Bar.barReads.widen)

  implicit val thingWrites: OWrites[Thing] = {
    case x: Foo => Foo.fooWrites.writes(x)
    case x: Bar => Bar.barWrites.writes(x)
  }
}

case class Foo(i: Int) extends Thing
object Foo {
  implicit val fooReads: Reads[Foo] = Json.reads[Foo]
  implicit val fooWrites: OWrites[Foo] = Json.writes[Foo]
}

case class Bar(s: String, t: List[Thing]) extends Thing
object Bar {
  implicit val barReads: Reads[Bar] = (
    (__ \ "s").read[String] and
      (__ \ "t").lazyRead(Reads.list[Thing](Thing.thingReads))
  )(Bar.apply _)

  implicit val barWrites: OWrites[Bar] = (
    (__ \ "s").write[String] and
      (__ \ "t").lazyWrite(Writes.list[Thing](Thing.thingWrites))
  )(unlift(Bar.unapply))
}

val thing: Thing = Bar("doomy doomy doom", List(Foo(24), Bar("doooom!", List(Foo(1), Foo(2), Foo(3))), Foo(42), Foo(126)))
val str = Json.stringify(Json.toJson(thing))
//{"s":"doomy doomy doom","t":[{"i":24},{"s":"doooom!","t":[{"i":1},{"i":2},{"i":3}]},{"i":42},{"i":126}]}
val thing1 = Json.parse(str).as[Thing]
// Bar(doomy doomy doom,List(Foo(24), Bar(doooom!,List(Foo(1), Foo(2), Foo(3))), Foo(42), Foo(126)))
thing1 == thing // true

链接:https://stackoverflow.com/questions/75596492/scala-play-json-nested-cyclic-dependency-json-parsing

英文:

Try to define custom codecs for the trait (without discriminator) and lazy codecs for the recursive type

import play.api.libs.json._
import play.api.libs.functional.syntax._
sealed trait Thing
object Thing {
implicit val thingReads: Reads[Thing] = Foo.fooReads.or[Thing](Bar.barReads.widen)
implicit val thingWrites: OWrites[Thing] = {
case x: Foo => Foo.fooWrites.writes(x)
case x: Bar => Bar.barWrites.writes(x)
}
}
case class Foo(i: Int) extends Thing
object Foo {
implicit val fooReads: Reads[Foo] = Json.reads[Foo]
implicit val fooWrites: OWrites[Foo] = Json.writes[Foo]
}
case class Bar(s: String, t: List[Thing]) extends Thing
object Bar {
implicit val barReads: Reads[Bar] = (
(__ \ "s").read[String] and
(__ \ "t").lazyRead(Reads.list[Thing](Thing.thingReads))
)(Bar.apply _)
implicit val barWrites: OWrites[Bar] = (
(__ \ "s").write[String] and
(__ \ "t").lazyWrite(Writes.list[Thing](Thing.thingWrites))
)(unlift(Bar.unapply))
}
val thing: Thing = Bar("doomy doomy doom", List(Foo(24), Bar("doooom!", List(Foo(1), Foo(2), Foo(3))), Foo(42), Foo(126)))
val str = Json.stringify(Json.toJson(thing))
//{"s":"doomy doomy doom","t":[{"i":24},{"s":"doooom!","t":[{"i":1},{"i":2},{"i":3}]},{"i":42},{"i":126}]}
val thing1 = Json.parse(str).as[Thing]
// Bar(doomy doomy doom,List(Foo(24), Bar(doooom!,List(Foo(1), Foo(2), Foo(3))), Foo(42), Foo(126)))
thing1 == thing // true

https://stackoverflow.com/questions/75596492/scala-play-json-nested-cyclic-dependency-json-parsing

huangapple
  • 本文由 发表于 2023年4月11日 03:33:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/75980137.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定