Skip to content

Include discriminator when serializing concrete type #96

@sam-veezoo

Description

@sam-veezoo

Is there a way to include the discriminator even when serializing the concrete type? Concretely, I'd like to instantiate the library in this piece of code and get the same output in both println statements:

sealed trait Base
case class Foo(name: String) extends Base

object Test {
  def test(): Unit = {
    val foo = Foo("Hello")
    val fooAsBase: Base = foo

    println(Json.toJson(fooAsBase).toString())    // expected: { "type": "Foo", "name": "Hello" }
    println(Json.toJson(foo).toString())          // expected: { "type": "Foo", "name": "Hello" }
  }
}

The ideomatic way to instantiate the library would only provide us with Writes[Base] used in the first println statement. I attempted to use generics in order to obtain suitable implicits for Writes[Foo] and Writes[Base] as follows:

object Base {
  implicit def writes[T <: Base]: Writes[T] =
    julienrf.json.derived.flat.owrites[Base](
      (__ \ "type").write[String]
    ).asInstanceOf[Writes[T]]
}

This used to work in play-json-derived-codes version 7.0.0 (together with play-json_2.12:2.8.2), however I end up with infinite recursion when using a more recent play-json-derived-codes version 10.1.0 (together with play-json_2.13:2.10.5):

at julienrf.json.derived.DerivedOWritesUtil$$anon$6.$anonfun$owrites$6(DerivedOWrites.scala:130)
at play.api.libs.json.OWrites$$anon$4.writes(Writes.scala:150)
at play.api.libs.json.OWrites.$anonfun$contramap$2(Writes.scala:76)
at play.api.libs.json.OWrites$$anon$4.writes(Writes.scala:150)
at play.api.libs.json.OWrites$$anon$4.writes(Writes.scala:149)
at julienrf.json.derived.TypeTagOWrites$$anon$2.$anonfun$owrites$2(typetags.scala:91)
at play.api.libs.json.OWrites$$anon$4.writes(Writes.scala:150)
at julienrf.json.derived.DerivedOWritesUtil$$anon$6.$anonfun$owrites$6(DerivedOWrites.scala:130)
...

Given my attempt is quite acrobatic, I am not sure whether the infinite recursion is actually a bug in the library.

Is there a way to achieve the expected result and obtain the same JSON serialization for the sealed trait as well as for the concrete case class?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions