You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scala Play JSON嵌套循环依赖解析:循环引用样例类的JSON互转

处理Scala循环引用样例类的JSON序列化与反序列化

针对你定义的存在嵌套循环引用的Scala样例类,下面以Circe(Scala生态中常用的JSON库)为例,实现JSON与样例类的相互转换,解决循环引用导致的序列化问题。

步骤1:引入依赖

在你的SBT项目中添加Circe相关依赖,核心模块负责基础序列化,extras模块用于处理循环引用:

libraryDependencies ++= Seq(
  "io.circe" %% "circe-core" % "0.14.6",
  "io.circe" %% "circe-generic" % "0.14.6",
  "io.circe" %% "circe-extras" % "0.14.6",
  "io.circe" %% "circe-parser" % "0.14.6"
)

步骤2:为样例类编写伴生对象并实现格式化器

利用Circe的半自动化推导,结合lazy val解决循环引用的初始化依赖问题:

import io.circe._
import io.circe.generic.semiauto._
import io.circe.extras.syntax._

case class DataSource(subQuery: Query, name: String)
object DataSource {
  // 用lazy val延迟初始化,避免循环依赖导致的初始化失败
  implicit lazy val encoder: Encoder[DataSource] = deriveEncoder[DataSource]
  implicit lazy val decoder: Decoder[DataSource] = deriveDecoder[DataSource]
}

case class JoinQuery(joinType: String, query: Query)
object JoinQuery {
  implicit lazy val encoder: Encoder[JoinQuery] = deriveEncoder[JoinQuery]
  implicit lazy val decoder: Decoder[JoinQuery] = deriveDecoder[JoinQuery]
}

case class Query(child: DataSource, joinQuery: Seq[JoinQuery])
object Query {
  implicit lazy val encoder: Encoder[Query] = deriveEncoder[Query]
  implicit lazy val decoder: Decoder[Query] = deriveDecoder[Query]
}

步骤3:处理循环引用的序列化与反序列化

Circe的extras模块提供了asJsonWithCircularReferences方法,会自动将循环引用的节点替换为JSON引用标记(如{"$ref":"#"}),避免栈溢出;反序列化时也能正确解析这些引用。

测试代码示例:

import io.circe.parser.decode

// 创建一个带循环引用的实例
val queryPlaceholder = Query(null, Nil)
val dataSource = DataSource(queryPlaceholder, "user_db")
val joinQuery = JoinQuery("inner_join", queryPlaceholder)
val finalQuery = queryPlaceholder.copy(child = dataSource, joinQuery = Seq(joinQuery))

// 序列化为JSON
val json = finalQuery.asJsonWithCircularReferences
println(json.spaces2)

// 反序列化回样例类
val decodedResult = decode[Query](json.noSpaces)
println(decodedResult)

关键说明

  • lazy val的作用:因为三个样例类互相引用,编码器/解码器的初始化存在依赖关系,lazy val会延迟初始化时机,确保所有依赖的格式化器都已准备好。
  • 循环引用处理:默认的JSON序列化会因循环引用导致栈溢出,Circe的asJsonWithCircularReferences通过生成JSON指针引用解决这个问题,反序列化时能自动还原引用关系。

如果使用Play JSON库,逻辑类似——同样用lazy val定义OFormat,但需要额外配置引用解析器来处理循环引用,Circe在这方面的支持更便捷。

内容的提问来源于stack exchange,提问作者Bill Goldberg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 13:07:35