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

China☆狼群 提交于 2019-12-11 03:22:54

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!