播放Json:定义一个解析[T],解析JSON数组并忽略某些元素

时间:2016-01-24 13:34:25

标签: json scala playframework playframework-2.0

我有一个抽象类型PolyType以及此类型的具体实现,TypeATypeBTypeC。目标是解析包含这三种类型的序列化表示的JSON数组。每个数组可以同时包含所有三种类型。

我正在使用以下Reads进行反序列化:

implicit val polyReads = new Reads[PolyType] {
    override def reads(json: JsValue): JsResult[PolyType] =
      json.validate(
        typeAReads.map(_.asInstanceOf[TypeA]) orElse
        typeBReads.map(_.asInstanceOf[TypeB]) orElse
        typeCReads.map(_.asInstanceOf[TypeC])
      )
}

最终,我可以像这样使用它来解析包含这三种类型的JSON数组:

val json: JsValue = { ... }
val result = json.validate[Seq[PolyType]] 

// => JsResult[Seq[PolyType]], Seq contains instances of A, B and C

这在概念上起作用。结果是Seq[PolyType],其中包含TypeATypeBTypeC的实例。请注意我不必手动处理Seq,例如我不需要明确检查输入是否代表一个json数组(如果没有,我得到一个JsError,这很好。)

但我真正想做的是:

首先,仅提取 TypeA个实例。这是因为TypeA包含正确解析TypeBTypeC所需的定义。因此ReadsTypeB的{​​{1}}是“动态的”,需要TypeC的具体实例。我没有为B和C定义那些“动态”TypeA的问题。

但我想知道:

  • 如何从相同的 json结构中首先提取Reads 以及以后
  • E.g。只是执行TypeA将无法工作,因为json数组还包含导致错误的其他两种类型。

1 个答案:

答案 0 :(得分:0)

我不知道TypeA如何用于提取TypeBTypeC,因此我只能告诉您如何提取TypeA的所有实例。首先,一些示例类型:

导入play.api.libs.json ._

trait PolyType

case class TypeA(a: String) extends PolyType

case class TypeB(b: String) extends PolyType

case class TypeC(c: String) extends PolyType

implicit val typeAReads: Reads[TypeA] = Json.reads[TypeA]
implicit val typeBReads: Reads[TypeB] = Json.reads[TypeB]
implicit val typeCReads: Reads[TypeC] = Json.reads[TypeC]

示例数据:

val json = Json.parse("""
    [
        {"a": "Some A"},
        {"b": "Some B"},
        {"c": "Some C"},
        {"c": "Other C"},
        {"a": "Other A"},
        {"b": "Other B"}
    ]
""")

然后,我定义Reads[Seq[TypeA]]首先尝试将validate JSON设为JsArray,然后将validate数组中的每个成员TypeA定义为collectimplicit val typeASeqReads = new Reads[Seq[TypeA]] { def reads(js: JsValue): JsResult[Seq[TypeA]] = { js.validate[JsArray].map { array => array.value.map(_.validate[TypeA]) .collect { case JsSuccess(a, _) => a } } } } 只有那些成功的人。

scala> json.validate[Seq[TypeA]]
res0: play.api.libs.json.JsResult[Seq[TypeA]] = JsSuccess(ListBuffer(TypeA(Some A), TypeA(Other A)),)

结果:

JsSuccess

注意事项:

  • 除非JSON不是数组,否则总是返回TypeA。因此,如果没有有效的Seq,则会返回空的TypeA
  • 要区分无效的Reads[Seq[PolyType]]和其他类型,将非常困难。

最后,您需要一个特殊的UnsafePointer<Void>来处理在列表中进行多次传递的要求。