I have a class hierarchy that represents filter types, and one of the types contains a list of the base types. I cannot figure out how to set up spray-json formats for these types because the formatters for the base type and the containing type need to refer to each other.
Let's start with a class hierarchy and json formats where the problematic parts are commented out:
object Filters {
sealed trait Filter
case class SimpleFilter(foo: String) extends Filter
case class DoubleFilter(foo: String, bar: String) extends Filter
implicit val simpleFormat = jsonFormat1(SimpleFilter)
implicit val doubleFormat = jsonFormat2(DoubleFilter)
// case class AndFilter(filters: List[Filter]) extends Filter
// implicit val andFormat = lazyFormat(jsonFormat1(AndFilter))
// (would really use a type field, keeping simple for example)
implicit val filterFormat = new RootJsonFormat[Filter] {
override def write(obj: Filter): JsValue = obj match {
case x: SimpleFilter => x.toJson
case x: DoubleFilter => x.toJson
// case x: AndFilter => x.toJson
}
override def read(json: JsValue): Filter = json.asJsObject.getFields("bar") match {
case Seq(_) => json.convertTo[DoubleFilter]
case Seq() => json.convertTo[SimpleFilter]
}
}
}
This compiles and works as expected, I can serialize and deserialize concrete filter subclasses as Filter no problem.
But let's comment in the AndFilter
stuff. Now there is trouble! With the declaration of andFormat
ahead of filterFormat
(as above), it won't compile because andFormat
needs filterFormat
:
Error:(17, 43) could not find implicit value for evidence parameter of type spray.json.DefaultJsonProtocol.JF[List[classpath.Filters.Filter]] implicit val andFormat = jsonFormat1(AndFilter)
Switching the order around to andFormat
after filterFormat
will let things compile. But of course I also want to add andFormat
-referencing clauses to filter
format, i.e. case x: AndFilter => x.toJson
in the write method and whatever including json.convertTo[AndFilter]
in the read method. And that doesn't compile either:
Error:(23, 34) Cannot find JsonWriter or JsonFormat type class for classpath.Filters.Filter with classpath.Filters.AndFilter case x: AndFilter => x.toJson
I can't find any way around this. I've tried spray-json's lazyFormat
but it doesn't help (only works for recursive self references, not a cross reference like this). Any ideas?