Play JSON formatter for Map[Int,_]

you can write your own reads and writes in play.

in your case, this would look like this:

implicit val mapReads: Reads[Map[Int, Boolean]] = new Reads[Map[Int, Boolean]] {
    def reads(jv: JsValue): JsResult[Map[Int, Boolean]] =
        JsSuccess(jv.as[Map[String, Boolean]].map{case (k, v) =>
            Integer.parseInt(k) -> v .asInstanceOf[Boolean]
        })
}

implicit val mapWrites: Writes[Map[Int, Boolean]] = new Writes[Map[Int, Boolean]] {
    def writes(map: Map[Int, Boolean]): JsValue =
        Json.obj(map.map{case (s, o) =>
            val ret: (String, JsValueWrapper) = s.toString -> JsBoolean(o)
            ret
        }.toSeq:_*)
}

implicit val mapFormat: Format[Map[Int, Boolean]] = Format(mapReads, mapWrites)

I have tested it with play 2.3. I'm not sure if it's the best approach to have a Map[Int, Boolean] on server side and a json object with string -> boolean mapping on the client side, though.


JSON only allows string keys (a limitation it inherits from JavaScript).


Thanks to Seth Tisue. This is my "generics" (half) way.

"half" because it does not handle a generic key. one can copy paste and replace the "Long" with "Int"

"Summary" is a type I've wanted to serialize (and it needed its own serializer)

/** this is how to create reader and writer or format for Maps*/
//  implicit val mapReads: Reads[Map[Long, Summary]] = new MapLongReads[Summary]
//  implicit val mapWrites: Writes[Map[Long, Summary]] = new MapLongWrites[Summary]
implicit val mapLongSummaryFormat: Format[Map[Long, Summary]] = new MapLongFormats[Summary]

This is the required implementation:

class MapLongReads[T]()(implicit reads: Reads[T]) extends Reads[Map[Long, T]] {
  def reads(jv: JsValue): JsResult[Map[Long, T]] =
    JsSuccess(jv.as[Map[String, T]].map{case (k, v) =>
      k.toString.toLong -> v .asInstanceOf[T]
    })
}

class MapLongWrites[T]()(implicit writes: Writes[T])  extends Writes[Map[Long, T]] {
  def writes(map: Map[Long, T]): JsValue =
    Json.obj(map.map{case (s, o) =>
      val ret: (String, JsValueWrapper) = s.toString -> Json.toJson(o)
      ret
    }.toSeq:_*)
}

class MapLongFormats[T]()(implicit format: Format[T]) extends Format[Map[Long, T]]{
  override def reads(json: JsValue): JsResult[Map[Long, T]] = new MapLongReads[T].reads(json)
  override def writes(o: Map[Long, T]): JsValue = new MapLongWrites[T].writes(o)
}