0
votes

I trying to implemente a json validations for a filter like this:

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 _)
}

as you can see on my LogicalClause, my children could be the a json with the same format of a LogicalClause or a json with the format of a ComparisonClause, but I can figure it our how to make this work.

Any suggestiong?

I'm getting the following error:

No Json deserializer found for type com.userzoom.analytics.explorerapi.models.LogicalClause. Try to implement an implicit Reads or Format for this type. [error]
((JsPath \ "children").read[LogicalClause] or (JsPath \ "children").read[ComparisonClause])

1
Pass a reference to the implicit instance itself when calling .read[SameType](myImplicit) for a child propertycchantep
@cchantep I tried like this: ( (JsPath \ "children").read[List[LogicalClause]] or (JsPath \ "children").lazyRead(Reads.list[IFilterClause](ComparisonClause)) ) but it does not work the code complains about the typeJean

1 Answers

0
votes

First you should put your implicits in the companion object, not in your case class. You can try this code, it should compile:

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
  }
}