play-json-alone icon indicating copy to clipboard operation
play-json-alone copied to clipboard

Serialize sealed traits

Open Sciss opened this issue 11 years ago • 6 comments

I think it would be great if the library not just handled case classes, but also sealed traits whose direct sub classes are case classes. My use case is in this Stackoverflow question.

I am now looking into a work around for writing a SealedTraitCompanion trait which has the appropriate apply and unapply methods. I would prefer to solve this now with reflection (instead of macros) because I need a quick solution, but probably that will not work because that needs to find implicit formats for the sub types.


I have a related question. Would it be possible for Json.format[A] to not look for the companion object of A but some auxiliary objects? That is to say, if I want a format for a sealed trait A, I don't want to enforce having JSON related methods on A.type, because the format should be independent.

Sciss avatar Jun 17 '13 10:06 Sciss

Actually, the best way to deal with sealed trait is the following (with an even more complicated case with recursive classes): https://gist.github.com/mandubian/5396793

BTW, Reflection is not all the philosophy of our API. If you need something dynamic, Jackson is there for that (even if it's not as nice ;) )

if you want to have a custom behavior, you shouldn't use the macro and write your format yourself and call what you need. The macro is just a helper and it's not meant to be very clever ;)

mandubian avatar Jun 17 '13 12:06 mandubian

Thanks. Looking at the gist, this looks like I'll have to write that bit for each and every trait I have, right? And then the writing part is also missing.

I see that all is macro based, so I won't come far with reflection.

I can come up with my own format, no problem, but I want to do this for a great number of traits and classes, and I really want an automatic mechanism for any sealed trait. I'll have a go at writing such a macro, never written any, so I don't know if this is straight forward or not. I'm a bit familiar with the AST stuff of Scala, so let's see...

Sciss avatar Jun 17 '13 13:06 Sciss

On Mon, Jun 17, 2013 at 3:12 PM, Sciss [email protected] wrote:

Thanks. Looking at the gist, this looks like I'll have to write that bit for each and every trait I have, right? And then the writing part is also missing.

actually I would write it as following (didn't compile it right now so can be erroneous):

sealed trait FooBar

case class Foo(name: string) extends FooBar object Foo { val fmt = Json.format[Foo] } case class Bar(age: Long) extends FooBar object Bar { val fmt = Json.format[Bar] }

object FooBar{ implicit val reader = __.read[Foo].map(:FooBar) orElse __.read[Bar].map(:FooBar) implicit val writer = Writes[FooBar}{ case f: Foo => Json.toJson(f)(Foo.fmt) case b: Bar => Json.toJson(b)(Bar.fmt) } }

remark that I just declare the implicit in FooBar object! (for Reads it's not a pb since they are covariant but for Writes it would be a pb as they are contravariant)

regards Pascal

I see that all is macro based, so I won't come far with reflection.

actually this is a strong choice to be fully typesafe in our API. For reflection, we believe jackson is good enough.

I can come up with my own format, no problem, but I want to do this for a great number of traits and classes, and I really want an automatic mechanism for any sealed trait.

you can write your own macro but it's not so simple ;);)

— Reply to this email directly or view it on GitHubhttps://github.com/mandubian/play-json-alone/issues/3#issuecomment-19543609 .

mandubian avatar Jun 17 '13 13:06 mandubian

I have my extension working now, if you want to have a look. It still has problems when the sealed trait sub types are nested, but otherwise seems fine. Output may look like this, i.e. for traits you have a map with class and data.

Sciss avatar Jun 18 '13 12:06 Sciss

Great effort :) Maybe you could even go further and let macro users customize the field names "class" and "data"...

Let think a bit more to see if it's a good idea ;)

Pascal

On Tue, Jun 18, 2013 at 2:17 PM, Sciss [email protected] wrote:

I have my extensionhttps://github.com/Sciss/play-json-sealed/blob/master/core/src/main/scala/play/api/libs/json/SealedTraitFormat.scalaworking now, if you want to have a look. It still has problems when the sealed trait sub types are nested, but otherwise seems fine. Output may look like this https://gist.github.com/Sciss/5804889, i.e. for traits you have a map with class and data.

— Reply to this email directly or view it on GitHubhttps://github.com/mandubian/play-json-alone/issues/3#issuecomment-19607332 .

mandubian avatar Jun 18 '13 15:06 mandubian

Yes absolutely. BTW I am still having severe problems with knownDirectSubclasses not working (Scala 2.10.2) randomly, it seems a Scalac bug which depends on the compilation order. Like I comment out the macro calls, compile, remove comments again, at some point all the formats are there. Not sure what to do about it. Perhaps should test if this problem persists in Scala 2.11 Snapshot.

Sciss avatar Jun 18 '13 16:06 Sciss