scala-play 2.4.11,是否可以以 case class 为键对 Map 进行反序列化?
scala-play 2.4.11, is it possible to desearialize Map with case class as key?
我正在尝试处理 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]
我得到异常:
地图 [ItemCategory,Long] 没有可用的隐式格式。
为什么?
它失败了,因为 play-json 对如何在 Item
.
中反序列化 itemCounters: Map[ItemCategory, Long]
属性 感到困惑
的确,如果key是String
,JSON映射可以直接处理。但是对于键中的其他结构化对象,它变得有点困难,比如问题中的 ItemCategory
。这样key的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)
对于另一种情况 类,您已经定义的简单格式应该可以正常工作,前提是它们按照从最具体到最不具体(从 Repository
到 Items
).
我正在尝试处理 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]
我得到异常: 地图 [ItemCategory,Long] 没有可用的隐式格式。
为什么?
它失败了,因为 play-json 对如何在 Item
.
itemCounters: Map[ItemCategory, Long]
属性 感到困惑
的确,如果key是String
,JSON映射可以直接处理。但是对于键中的其他结构化对象,它变得有点困难,比如问题中的 ItemCategory
。这样key的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)
对于另一种情况 类,您已经定义的简单格式应该可以正常工作,前提是它们按照从最具体到最不具体(从 Repository
到 Items
).