scala-play 2.4.11,是否可以以案例类为键对地图进行去角化?



我正在尝试处理play-json,但它进展不顺利。 这是我的案例类

sealed case class Items(items: List[Item])
sealed case class Item(path: String, itemCounters: Map[ItemCategory, Long])
sealed case class ItemCategory(repository: Repository)
sealed case class Repository(env: String)

在这里,我正在尝试解析 json:

implicit lazy val repositoryFormat = Json.format[Repository]
implicit lazy val itemCategoryFormat = Json.format[ItemCategory]
implicit lazy val itemFormat = Json.format[Item]
implicit lazy val itemsFormat = Json.format[Items]
Json.parse(str).as[Items]

我得到例外:没有可用的 Map[ItemCategory,Long] 的隐式格式。

为什么?

它失败是因为play-json对如何在Item中反序列化itemCounters: Map[ItemCategory, Long]属性感到困惑。

事实上,如果密钥是String,则可以直接处理 JSON 映射。但是对于键中的其他结构化对象,例如问题中的ItemCategory,它变得更加困难。当然,具有这种密钥的 JSON 不能{ "repository": { "env": "demo" } }: 1

因此,我们需要明确这种 Map 的反序列化。我假设ItemCategory的键是基础ItemCategory.repository.env值,但它可以是任何其他属性,具体取决于您的有效数据模型。

我们为这种映射提供了一个Reads实现:

implicit lazy val itemCategoryMapReads = new Reads[Map[ItemCategory, Long]] {
override def reads(jsVal: JsValue): JsResult[Map[ItemCategory, Long]] = {
JsSuccess(
// the original string -> number map is translated into ItemCategory -> Long
jsVal.as[Map[String, Long]].map{
case (category, id) => (ItemCategory(Repository(category)), id)
}
)
}
}

以及相应的Format(带有Writes的存根,我们现在不需要(:

implicit lazy val itemCategoryMapFormat = Format(itemCategoryMapReads, (catMap: Map[ItemCategory, Long]) => ???)

基本 JSON 现已正确映射:

val strItemCat =
"""
| {
|   "rep1": 1,
|   "rep2": 2,
|   "rep3": 3
| }
""".stripMargin
println(Json.parse(strItemCat).as[Map[ItemCategory, Long]])
// Map(ItemCategory(Repository(rep1)) -> 1, ItemCategory(Repository(rep2)) -> 2, ItemCategory(Repository(rep3)) -> 3)

对于其他事例类,您已经定义的简单格式应该可以正常工作,前提是它们是按从最具体到最不具体的顺序(从RepositoryItems(声明的。

最新更新