2016-03-01 57 views
1

在Scala中,我有以下的数据结构(Item名称始终相同Container内是唯一的):播放的Json写入:Scala的SEQ到JSON对象

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")) 
)) 

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

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

I guess一个可能的解决方案可能是将Container(Seq[Item])转换为Map[String, Seq[String]],其中每个键对应于项目的名称和项目元素的值,并让API执行其余的操作(可能会隐式写入映射,阅读JSON时至少是这种情况)。

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

回答

2

我不认为你应该不必担心速度在这里(或至少验证它是担心之前的一个问题),并转换成地图可能是最简单的选择。另一种,这很可能不执行任何更好的,就是:

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,但会导致冲突与地图。)

+0

你关于表演可能是正确的。但是,您的解决方案不仅允许重复名称,而且还保留更好的元素顺序,谢谢! – ceran