问题
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?
回答1:
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
.
回答2:
You need to define a play.api.libs.json.Format for MyEnum.Value which translates your enum to and from a string representation. Such as the following:
import play.api.libs.json._
object MyEnum extends Enumeration {
type MyEnum = Value
val Val1 = Value("val1")
val Val2 = Value("val2")
val Val3 = Value("val3")
implicit val myEnumWrites = new Writes[Value]{
def writes(o:Value)=JsString(o.toString)
}
}
a more complete format (read and write) for MyEnum could look like
implicit val myEnumFormat = new Format[Value]{
def writes(o:Value)=JsString(o.toString)
def reads(json:JsValue):JsResult[Value]=json match {
case JsString("val1") =>JsSuccess(Val1)
case JsString("val2") =>JsSuccess(Val2)
case JsString("val3") =>JsSuccess(Val3)
case other => JsError(s"$other is not a valid value for MyEnum")
}
}
Using Enumeration is not advised. It can generally be replaced by either a sealed trait and a hierarchy of case object/case classes OR by using a java enumeration.
来源:https://stackoverflow.com/questions/25897921/how-to-serialize-a-mapcustomtype-string-to-json