Scala使用读取验证递归JSON(Play Framework)

时间:2017-11-20 14:59:53

标签: json scala playframework

我尝试为这样的过滤器实现json验证:

import play.api.libs.json._
import play.api.libs.functional.syntax._


trait IFilterClause

case class ComparisonClause(operand: String, operator: String, value: String, valueType: String) extends IFilterClause{
  implicit val comparisonClauseReads: Reads[ComparisonClause] = (
    (JsPath \ "operand").read[String] and
    (JsPath \ "operator").read[String] and
    (JsPath \ "value").read[String] and
    (JsPath \ "value_type").read[String]
  )(ComparisonClause.apply _)
}

case class LogicalClause(operator: String, children: List[IFilterClause]) extends IFilterClause {
  implicit lazy val logicalClauseReads: Reads[IFilterClause] = (
    (JsPath \ "logical_operator").read[String] and
      ((JsPath \ "children").read[LogicalClause] or (JsPath \ "children").read[ComparisonClause])
  )(LogicalClause.apply _)
}

正如你在我的LogicalClause上看到的那样,我的孩子们可能是一个具有相同格式的LogicalClause的json或者一个具有ComparisonClause格式的json,但我可以想象它是如何使这个工作的。

有任何建议吗?

我收到以下错误:

  

找不到类型的Json反序列化器   com.userzoom.analytics.explorerapi.models.LogicalClause。尝试   为此类型实现隐式读取或格式。 [错误]
  ((JsPath \“children”)。读取[LogicalClause]或(JsPath \   “儿童”)。读[ComparisonClause])

1 个答案:

答案 0 :(得分:0)

首先,您应该将implicit放在随播对象中,而不是放在case class中。你可以尝试这段代码,它应该编译:

import play.api.libs.json._
import play.api.libs.functional.syntax._

trait IFilterClause

case class ComparisonClause(operand: String, operator: String, value: String, valueType: String) extends IFilterClause
object ComparisonClause {
  implicit val comparisonClauseReads: Reads[ComparisonClause] = (
    (JsPath \ "operand").read[String] and
      (JsPath \ "operator").read[String] and
      (JsPath \ "value").read[String] and
      (JsPath \ "value_type").read[String]
  )(ComparisonClause.apply _)
}

case class LogicalClause(operator: String, children: List[IFilterClause]) extends IFilterClause
object LogicalClause {
  implicit lazy val logicalClauseReads: Reads[LogicalClause] = (
    (JsPath \ "logical_operator").read[String] and
      (JsPath \ "children").read[List[IFilterClause]]
  )(LogicalClause.apply _)
}

object IFilterClause {
  implicit lazy val reader: Reads[IFilterClause] = {
    // needed because Reads is invariant
    val reader1 = ComparisonClause.comparisonClauseReads.map(f => f: IFilterClause)
    lazy val reader2 = LogicalClause.logicalClauseReads.map(f       => f: IFilterClause)
    reader1 orElse reader2
  }
}