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

Play框架中sealed抽象类实现Json反序列化隐式Reads的方法

问题原因

Play JSON 提供的自动宏派生工具Json.reads无法处理子类为私有类型的密封类:

  • 自动派生要求密封类的所有子类均为公开类型、且和密封类在同一编译单元内,宏才能扫描到所有子类完成派生
  • 你当前的WeekGranularity是Granularity伴生对象的私有类,宏无法识别所以抛出no known subclasses错误
正确实现方案

你当前的Writes逻辑是直接将Granularity实例序列化为对应的名称字符串,只需要配套实现对应逻辑的手动Reads即可,不需要依赖自动派生:

步骤1:在Granularity伴生对象中实现序列化逻辑

把读写逻辑统一定义在类型伴生对象中,无需每次使用时单独声明:

import play.api.libs.json._

sealed abstract class Granularity(name: String, windowSize: String) {
  // 原有属性和方法
}

object Granularity {
  final private case class WeekGranularity(name: String, windowSize: Int) extends Granularity("week", "'7' day") {
    // 确保toString返回和序列化值一致的字符串,这里示例返回"week"
    override def toString: String = name
  }

  val Week: Granularity = WeekGranularity(name = "week", windowSize = 1)
  // 后续新增其他粒度直接加对应val即可
  // val Day: Granularity = DayGranularity(name = "day", windowSize = 1)

  // 手动实现Reads:读取JSON字符串,匹配对应Granularity实例
  implicit val granularityReads: Reads[Granularity] = Reads.stringReads.collect(
    JsonValidationError("不支持的粒度类型")
  ) {
    case "week" => Week
    // 新增粒度后在这里加匹配分支即可
    // case "day" => Day
  }

  // 原有Writes也可以移到这里统一管理
  implicit val granularityWrites: Writes[Granularity] = Writes(granularity => JsString(granularity.toString))

  // 也可以直接用Format整合读写逻辑
  implicit val granularityFormat: Format[Granularity] = Format(granularityReads, granularityWrites)
}

步骤2:自动派生Meta的序列化实例

Granularity的隐式序列化实例定义在伴生对象后,Play JSON可以自动识别,直接派生Meta的序列化实例即可:

import play.api.libs.json._

case class Meta(granularity: Granularity)
object Meta {
  // 自动派生时会自动读取Granularity伴生对象的隐式实例
  implicit val metaFormat: OFormat[Meta] = Json.format[Meta]
}

配置完成后测试代码中不需要额外声明隐式实例,直接调用asOpt[Meta]即可正常反序列化。

可选方案:用自动派生处理密封类

如果后续子类多、不想手动维护匹配分支,可以调整结构适配自动派生规则:

  • 将私有子类改为公开类型,放在Granularity伴生对象内
  • 配合Json.config配置密封类的序列化规则,比如用字段名作为鉴别器、或者直接用子类名作为序列化值
    不过对于你当前的简单字符串序列化场景,手动实现Reads的成本更低、性能也更好。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 13:27:02