Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recursive OFormat problem (not sure if this is a limit in the language or play or your library) #35

Open
jarlah opened this issue Jun 29, 2016 · 4 comments

Comments

@jarlah
Copy link

jarlah commented Jun 29, 2016

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?

@jarlah
Copy link
Author

jarlah commented Jun 29, 2016

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?

@julienrf
Copy link
Owner

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

@julienrf
Copy link
Owner

Thanks for reporting that, by the way!

@julienrf
Copy link
Owner

julienrf commented Jul 1, 2016

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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants