使用密封的特征/案例类播放JSON:无限递归

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用密封的特征/案例类播放JSON:无限递归相关的知识,希望对你有一定的参考价值。

我有一个代码,我尝试通过为基本特征定义自定义Writes来自定义一堆案例类的JSON序列化。我得到无限递归/堆栈溢出。

我创建了一个简化的示例 - 如果有人知道如何解决它,请告诉我。

import play.api.libs.json._

sealed trait Person {
  val name: String
}

final case class Teacher(name: String, salary: Int) extends Person
final case class Student(name: String, grade: Int) extends Person

implicit val teacherWrites: Writes[Teacher] = Json.writes[Teacher]
implicit val studentWrites: Writes[Student] = Json.writes[Student]

val ThePersonWrites: Writes[Person] = Writes(person => {
  Json.writes[Person].writes(person).as[JsObject] - "_type"
})

implicit val personWrites: Writes[Person] = ThePersonWrites

val people = List[Person] (
  Teacher("Jane Doe", 40000),
  Student("Alice", 5),
  Student("Bob", 7)
  )

Json.prettyPrint(Json.toJson(people))
答案

你需要play-json-derived-codecs

import play.api.libs.json._
import julienrf.json.derived

sealed trait Person {
  val name: String
}

object Person {
  implicit val jsonFormat: OFormat[Person] = derived.oformat[Person]()
}

final case class Teacher(name: String, salary: Int) extends Person
final case class Student(name: String, grade: Int) extends Person


val people = List[Person] (
  Teacher("Jane Doe", 40000),
  Student("Alice", 5),
  Student("Bob", 7)
)

println(Json.prettyPrint(Json.toJson(people)))

在这里看到scalafiddle

另一答案

这应该这样做:

import play.api.libs.json._

sealed trait Person {
  val name: String
}

final case class Teacher(name: String, salary: Int) extends Person
final case class Student(name: String, grade: Int) extends Person

implicit val teacherWrites: Writes[Teacher] = Json.writes[Teacher]
implicit val studentWrites: Writes[Student] = Json.writes[Student]

implicit val personWrites: Writes[Person] = Writes[Person] {
  case t: Teacher => Json.toJson(t)(teacherWrites)
  case s: Student => Json.toJson(s)(studentWrites)
}

val people = List[Person] (
  Teacher("Jane Doe", 40000),
  Student("Alice", 5),
  Student("Bob", 7)
)

Json.prettyPrint(Json.toJson(people))

诀窍是明确添加teacherWritesstudentWrites。因为它们都是Persons,在它们识别它们之前再次调用你的personWrites,因此堆栈溢出。

以上是关于使用密封的特征/案例类播放JSON:无限递归的主要内容,如果未能解决你的问题,请参考以下文章

带有 Play 2.2 库的密封特征的无噪声 JSON 格式

抽象类上的 Json.reads(不支持密封特征:没有已知的子类)

用于编码/解码 arity 0 的密封特征实例的 Circe 实例?

如何使用 circe 将密封特征案例对象转换为字符串

火花数据框密封特征类型

如何使用数据类在 Kotlin 中解决“无法编写 JSON:无限递归 (***Error)”?