play-json-derived-codecs
play-json-derived-codecs copied to clipboard
Recursive OFormat problem (not sure if this is a limit in the language or play or your library)
neither
sealed trait SillyTrait
case class SillyObject(silly: SillyObject) extends SillyTrait
object SillyTrait {
implicit lazy val format: OFormat[SillyTrait] = flat.oformat((__ \ "type").format[String])
}
or
sealed trait SillyTrait
case class SillyObject(silly: SillyObject) extends SillyTrait
object SillyObject {
implicit lazy val format = Json.format[SillyObject]
}
object SillyTrait {
implicit lazy val format: OFormat[SillyTrait] = flat.oformat((__ \ "type").format[String])
}
or
sealed trait SillyTrait
case class SillyObject(silly: SillyObject) extends SillyTrait
object SillyObject {
implicit lazy val format = Json.format[SillyObject]
}
can be used as a representation for a json payload where the type SillyObject can be nested within SillyObject.
Is this a known limitation with Scala or Play? Can this be solved by adding extra magic with play-son-derived-codecs?
Its fully possible to do manually with laziness as described in http://stackoverflow.com/questions/27443335/scala-play-2-3-framework-json-validate-recursively extract:
(which is also described in official play doc: https://www.playframework.com/documentation/2.5.x/ScalaJsonCombinators#recursive-types)
case class RuleJson(
`type`: String,
attribute: Option[String],
operator: Option[String],
value: String,
isValueProcessed: Option[Boolean],
aggregator: Option[String],
conditions: Seq[RuleJson]
)
object RuleJson {
implicit val reads: Reads[RuleJson] = (
(__ \ "type").read[String] and
(__ \ "attribute").readNullable[String] and
(__ \ "operator").readNullable[String] and
(__ \ "value").read[String] and
(__ \ "is_value_processed").readNullable[Boolean] and
(__ \ "aggregator").readNullable[String] and
(__ \ "conditions").lazyReadNullable[Seq[RuleJson]](Reads.seq(RuleJson.reads))
.map(opt => opt.toSeq.flatten)
)(RuleJson.apply _)
}
Shouldn't either the play library or this library be capable of figuring out the recursive formats with laziness?
Hm, the first snippet of code should work as is. I will investigate why it doesn’t.
In the meantime, it seems that you can workaround the issue as follows:
sealed trait SillyTrait
case class SillyObject(silly: Option[SillyObject]) extends SillyTrait
object SillyObject {
implicit val format: OFormat[SillyObject] = flat.oformat((__ \ "type").format[String])
}
object SillyTrait {
implicit lazy val format: OFormat[SillyTrait] = flat.oformat((__ \ "type").format[String])
}
Thanks for reporting that, by the way!
The last example you gave (RuleJson
) should work.
Here, the problem is that the recursivity is on a leaf, and not on the hierarchy root type. I’m still thinking of a better derivation mechanism to handle that case… Stay tuned!