基于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)
关键说明
- 移除自动生成的父类Reads:
Json.reads[Parent]无法处理多态场景,必须手动实现。 - 动态分支解析:通过读取
type字段的值,将JSON转发到对应的子类解析器。如果后续新增子类,只需在flatMap的case分支中添加对应的类型判断即可。 - 隐式作用域顺序:子类的
Reads必须在父类Reads之前定义,确保解析时能找到对应的隐式实例。
内容的提问来源于stack exchange,提问作者abw
相关产品推荐
相关产品推荐

