播放 Json 写入:Scala Seq 到 Json 对象

Play Json Writes: Scala Seq to Json Object

在 Scala 中,我有以下数据结构(Item 名称在同一个 Container 中总是唯一的):

case class Container(content: Seq[Item])
case class Item(name: String, elements: Seq[String])

示例实例:

val container = Container(Seq(
    Item("A", Seq("A1", "A2")),
    Item("B", Seq("B1", "B2"))
))

我想要做的是定义一个 Writes[Container] 产生以下 JSON:

{
    "A": ["A1", "A2"],
    "B": ["B1", "B2"]
}

猜测一个可能的解决方案是将Container(Seq[Item])转换为Map[String, Seq[String]],其中每个键对应一个项目的名称,值对应一个item 的元素,然后让 API 完成剩下的工作(可能存在映射的隐式写入,至少在读取 JSON 时是这种情况)。

但是:这种方法为每个 Container 创建了一个新的 Map,除了生成 JSON 没有其他目的。有很多 Container 个实例需要转换为 JSON,所以我认为这种方法相当昂贵。我还能怎么做?

我认为您不必担心这里的速度(或者至少在担心之前确认这是一个问题),转换为地图可能是最简单的选择。另一种可能效果不佳的替代方法是:

val customWrites: Writes[Container] = new Writes[Container] {
  override def writes(container: Container): JsValue = {
    val elems = container.content.map(
        elem => elem.name -> Json.toJsFieldJsValueWrapper(elem.elements))
    Json.obj(elems: _*)
  }
}

(显式转换为 JsValueWrapper - 通常是隐式的 - 在这种情况下似乎是必要的,原因我不完全理解或没有时间深入研究。This answer 有一些细节。)

此方法的一个优点是它将处理 Item 具有重复名称的对象(这当然是合法的 JSON 但会导致与地图发生冲突。)