Open manuelbernhardt opened 9 years ago
In general you can implement this example like this:
sealed trait Parent
case class A(b: B) extends Parent
case class B(foo: String) extends Parent
object Parent {
implicit val bJson: JSON[B] = deriveJSON[B]
implicit val parentJson: JSON[Parent] = deriveJSON[Parent]
}
println(toJSON(A(B("hello")): Parent))
it will print:
{"b":{"foo":"hello"},"type":"A"}
It works, because ToJSON
/FromJSON
and JSON
type classes are invariant and deriveJSON[Parent]
generates serializer only for type Parent
. This also mean, that deriveJSON[Parent]
will not work for toJSON(A(...))
or toJSON(B(...))
. That's why you also need another serializer for B
.
That said both of these scenarios:
sealed trait Parent
case class A(b: Option[B]) extends Parent
case class B(a: Option[A]) extends Parent
and
sealed trait Parent
case class A(b: Parent) extends Parent
case class B(A: String) extends Parent
are not supported at the moment. Do you think that one/both of these scenarios are also in the scope of this issue?
This may go wrong depending on which (random? alphabetical?) order the subclasses are detected because the macro then generates code containing a forward reference. I'm not sure how easy this is to fix. I know the Play JSON macro has a mechanism for warning of such cases (i.e. it fails if it can't find an implicit JSON format in scope), one idea would be to take into account the order of declaration of the subclasses in code by doing a tree traversal and sort the subclasses discovered at compile-time according to that order (but I don't know how easy that is, I have only a limited experience with macros). Or another approach could be to do a topological sort on the subclasses should they reference symbols that are also subclasses of the trait.