ceran
ceran

Reputation: 1412

Play Json Writes: Scala Seq to Json Object

In Scala, I have the following data structure (Item names are always unique within the same Container):

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

Example instance:

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

What I want to do is to define a Writes[Container] that produces the following JSON:

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

I guess a possible solution could be to transform the Container(Seq[Item]) into a Map[String, Seq[String]] where each key corresponds to an item's name and the value to an item's elements and let the API do the rest (there's probably an implicit write for maps, at least this is the case when reading JSON).

But: this approach creates a new Map for every Container with no other purpose than producing JSON. There are a lot Containerinstances that need to be transformed to JSON, so I assume this approach is rather expensive. How else could I do this?

Upvotes: 1

Views: 1326

Answers (1)

Mikesname
Mikesname

Reputation: 8901

I don't think you should necessarily worry about the speed here (or at least verify that it is a problem before worrying about it), and converting to a map is probably the easiest option. An alternative, which may well not perform any better, is:

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: _*)
  }
}

(The explicit conversion to a JsValueWrapper - which is normally implicit - seems to be necessary in this context for reasons I don't entirely understand or have time to delve into. This answer has some details.)

One advantage of this method is that it will handle Item objects with duplicate names (which of course is legal JSON but would cause collisions with a map.)

Upvotes: 2

Related Questions