如何将Map [CustomType,String]序列化为JSON

时间:2014-09-17 18:35:06

标签: scala playframework playframework-json

鉴于以下Enumeration ...

object MyEnum extends Enumeration {

  type MyEnum = Value

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

import MyEnum._

...以及以下Map ...

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

...我需要将m转换为JSON:

import play.api.libs.json._

val js = Json.toJson(m)

最后一个语句无法编译,因为编译器找不到类型scala.collection.immutable.Map[MyEnum.Value,String]的Json序列化程序。

问题:由于Play确实为类型scala.collection.immutable.Map[String,String]提供了序列化程序,而我的枚举实际上包含字符串,有没有办法重用默认的JSON序列化程序?

2 个答案:

答案 0 :(得分:5)

The built-in Reads objects不要为密钥中的Reads参数设置Map。你可以这样做:

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) 
}

根据您的价值观,您会得到:

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

如果您愿意,可以加强A上的限制,使其不适用于任何AnyRef

答案 1 :(得分:1)

您需要为MyEnum.Value定义一个play.api.libs.json.Format,它将您的枚举转换为字符串表示形式。如下:

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)
  }
} 

MyEnum的更完整格式(读取和写入)可能看起来像

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")
  }
}

不建议使用枚举。它通常可以由密封特征和案例对象/案例类的层次结构或使用java枚举替换。