【发布时间】:2015-08-11 16:18:20
【问题描述】:
我有这个:
sealed trait Block
sealed case class Header(param1: String,
param2: String,
...) extends Block
...
(more sealed case classes that follows the same pattern)
稍后,我将这些块分组到一个 Seq 中,如下所示:
val blocks: Seq[Block with Product with Serializable] = Seq(structure.header, structure.body, ...)
我想将每个块序列化为 Json(使用 Play)。我这样做如下:
blocks.map{
x =>
serializeBlock(x)
}
“serializeBlock”的定义:
def serializeBlock[A<:Block](block:A): String = {
block match {
case block: Header => Json.toJson(block).toString()
case block: Body => Json.toJson(block).toString()
... n-times for every possible case class that mixes the block trait
}
}
我对每个具体块(标题、正文...)都有读取器和写入器,但是,如您所见,当我在 Seq 中混合这些块时,Scala 将其视为通用类型块,因此我正在做与每种可能的块类型匹配的模式(隐式转换?)。如果我只是在 Map Play 中调用“Json.toJson”,则会抱怨找不到“块”类型的读取器/写入器。
“块”是相对较大的 JSON 的片段。我正在获取 JSON,我将其拆分为合格的“块”,然后将其作为字符串保存在数据库中:
“大”JSON:
{
"header" : {
"param1" : "",
...
},
"body" : {
"param1" : "",
...
}
...
}
块
{
"param1" : "",
...
}
我的问题是:有没有办法在不重复 n 次“block: type”模式的情况下进行序列化?我的意思是:有没有办法获得该块的具体类型(知道 Seq 被键入为超类“块”而不是该块的“具体”类型)?
编辑
我为每个块都有一个读取器/写入器,如下所示:
implicit val headerReader: Reads[Header] = (
(JsPath \ "param1").read[String] and
(JsPath \ "param2").read[String] and
...
)(Header.apply _)
implicit val headerWriter: Writes[Header] = (
(JsPath \ "param1").write[String] and
(JsPath \ "param2").write[String] and
...
)(unlift(Header.unapply))
编辑 2:
Shapeless 是解决这个问题的方法吗?
编辑 3:
正如 Andrzej Jozwik 所说:“param1”和“param2”是我在这里用来定义我的 JSON 结构的“通配符”参数。每个块都有不同的参数。
【问题讨论】:
-
block的case有什么不同的行为吗?
-
@SergeyLagutin 不,每个案例类只是一个用于转换传入/传出 JSON 的容器。
-
我的意思是模式匹配中的情况彼此不同?或者除了类型之外它们是否相同?
-
@SergeyLagutin 哦,对不起。是的,每个案例都做同样的事情 (Json.toJson(x).toString())。唯一的区别是每个块的类型。
-
如果每个 Block 都包含相同的字段 (param1,param2) - 你不需要很多类型。您需要转换为 Map[String,Block]。
标签: json scala playframework play-json