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

基于Scala Play Framework解析JSON:如何处理可变数组元素?

Play Framework 多态JSON序列解析解决方案

你遇到的核心问题是:Play Framework的自动生成Reads无法处理密封特质的多态解析——它不知道如何根据JSON中的type字段选择对应的子类解析器。以下是正确的实现方案:

核心思路

手动实现Reads[Parent],通过读取JSON中的type字段值,动态匹配对应的子类解析逻辑,替代自动生成的Json.reads[Parent]。

完整代码实现

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

sealed trait Parent { def title: String }
case class One(`type`: String, title: String, weird: String, other: Int) extends Parent
case class Two(`type`: String, title: String, another_weird: String, another: String) extends Parent

case class SearchResponse(result: Seq[Parent], metadata: Seq[String])

// 先定义子类的Reads(必须在父类Reads之前定义,确保隐式作用域可见)
implicit val oneReader: Reads[One] = Json.reads[One]
implicit val twoReader: Reads[Two] = Json.reads[Two]

// 手动实现Parent的多态Reads:根据type字段分支解析
implicit val parentReader: Reads[Parent] = Reads { json =>
  (json \ "type").validate[String].flatMap {
    // 这里的type值要和JSON中实际的字段值对应,比如JSON里type是"one"就匹配One类
    case "one" => json.validate[One]
    case "two" => json.validate[Two]
    case unknown => JsError(s"无法识别的类型: $unknown")
  }
}

// 自动生成SearchResponse的Reads(此时Parent的Reads已正确定义)
implicit val searchResponseReader: Reads[SearchResponse] = Json.reads[SearchResponse]

// 测试解析示例
val testJson = Json.parse("""
{
  "result": [
    {"type": "one", "title": "第一个项目", "weird": "特殊值", "other": 100},
    {"type": "two", "title": "第二个项目", "another_weird": "另一个特殊值", "another": "测试文本"}
  ],
  "metadata": ["页码:1", "总数:2"]
}
""")

val parseResult = Json.fromJson[SearchResponse](testJson)
println(parseResult)

关键说明

  1. 移除自动生成的父类Reads:Json.reads[Parent]无法处理多态场景,必须手动实现。
  2. 动态分支解析:通过读取type字段的值,将JSON转发到对应的子类解析器。如果后续新增子类,只需在flatMap的case分支中添加对应的类型判断即可。
  3. 隐式作用域顺序:子类的Reads必须在父类Reads之前定义,确保解析时能找到对应的隐式实例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 07:10:14