Search code examples
scalaplayframeworkplayframework-json

How to serialize a Map[CustomType, String] to JSON


Given the following Enumeration...

object MyEnum extends Enumeration {

  type MyEnum = Value

  val Val1 = Value("val1")
  val Val2 = Value("val2")
  val Val3 = Value("val3")
} 

import MyEnum._

... and the following Map...

val m = Map(
  val1 -> "one",
  val2 -> "two",
  val3 -> "three"
)

... I need to transform m to JSON:

import play.api.libs.json._

val js = Json.toJson(m)

The last statement doesn't compile because the compiler doesn't find a Json serializer for type scala.collection.immutable.Map[MyEnum.Value,String].

Question: Since Play does provide a serializer for type scala.collection.immutable.Map[String,String], and my enumeration actually contains strings, is there a way to reuse the default JSON serializer?


Solution

  • The built-in Reads objects don't define a Reads for a Map that's parametric in the key. You could do something like:

    implicit def looserMapWrites[A <: AnyRef, B : Writes]: Writes[Map[A, B]] = Writes { o => 
      Json.toJson(o.map { case (key, value) => 
        key.toString -> value 
      })(Writes.mapWrites) 
    }
    

    And with your values above, you get:

    scala> Json.toJson(m)(looserMapWrites)
    res1: play.api.libs.json.JsValue = {"val1":"one","val2":"two","val3":"three"}
    

    If you want to, you can tighten those bounds on A to make it not applicable to any AnyRef.