Donnerstag, 9. Januar 2014

Using Play JSON Combinators to fill a Map

Reads[T] to case object

Play Framework provides a neat library to turn JSON into Scala Objects. Typically, you would use play.api.libs.json.Reads[T] like this:
case class Vote (
    yes: Int,
    no: Int,
    maybe: Int
)

implicit val voteReads = (
    (__ \ "yes").read[Int] and
    (__ \ "no").read[Int] and
    (__ \ "maybe").read[Int]
)(Vote.apply _)
This will turn a flat JSON dictionary representing the results of a vote into a case object.

Reads[T] to Map

However, you might not always want to create case objects from your JSON input. You might want to collect the results from the Reads[T] in a Map, mapping from the choices in a vote to the number of votes. It is not immediately obvious how to achieve this, but keep in mind that the above statement can also be represented as:
implicit val voteReads = (
    (__ \ "yes").read[Int] and
    (__ \ "no").read[Int] and
    (__ \ "maybe").read[Int]
)((yes: Int, no: Int, maybe: Int) => new Vote(yes, no, maybe)) 
With this in mind, you can easily replace the creation of the case object with the creation of a Map using Reads Combinators like this:
import play.api.libs.json._
import play.api.libs.functional.syntax._

implicit val voteReads = (
    (__ \ "yes").read[Int] and
    (__ \ "no").read[Int] and
    (__ \ "maybe").read[Int]
)((yes: Int, no: Int, maybe: Int) => Map("yes" -> yes, "no" -> no, "maybe" -> maybe))

val js = Json.obj( "yes" -> 7, "no" -> 11, "maybe" -> 13)
js.validate
res0: play.api.libs.json.JsResult[scala.collection.immutable.Map[String,Int]] =
 JsSuccess(Map(yes -> 7, no -> 11, maybe -> 13),)

Keine Kommentare:

Kommentar veröffentlichen