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

jsonDiscriminator does not add field when encoding #1197

Open
funrep opened this issue Dec 16, 2024 · 2 comments
Open

jsonDiscriminator does not add field when encoding #1197

funrep opened this issue Dec 16, 2024 · 2 comments
Labels
good first issue Good for newcomers

Comments

@funrep
Copy link

funrep commented Dec 16, 2024

When encoding toJson and using @jsonDiscriminator("type") on sealed traits the output string does not have type field as expected. In this example BarNotOk is expected to parse, but does not with error (missing hint 'type').

  • BarNotOk uses derives JsonCodec and is expected to add type field when encoding/decoding, but encoding is not working as expected and the type field is not added when running toJson.
  • BarOk uses a work-around to get the expected behaviour, specifying a custom encoder that explicitly adds the type field. This has the expected behaviour but requires extra work-around code.
scalaVersion := "3.5.0"

libraryDependencies ++= Seq(
  "dev.zio" %% "zio" % "2.0.15",
  "dev.zio" %% "zio-json" % "0.7.3"
)
import zio._
import zio.json._

@jsonDiscriminator("type")
sealed trait Foo derives JsonCodec

@jsonDiscriminator("type")
case class BarOk(bar: Int) extends Foo derives JsonDecoder

@jsonDiscriminator("type")
case class BarNotOk(bar: Int) extends Foo derives JsonCodec

object BarOk:
  given JsonEncoder[BarOk] = JsonEncoder
    .derived[BarEncoder]
    .contramap[BarOk] { case BarOk(bar) =>
      BarEncoder(bar)
    }

case class BarEncoder(bar: Int, `type`: String = "BarOk") derives JsonEncoder

object HelloWorld extends ZIOAppDefault {
  def run =
    val bar1 = BarNotOk(bar = 42)
    val barStr1 = bar1.toJson
    val bar2 = BarOk(bar = 42)
    val barStr2 = bar2.toJson
    for
      _ <- Console.printLine(barStr1)
      _ <- Console.printLine(barStr2)
      _ <- ZIO
        .fromEither(barStr1.fromJson[Foo])
        .flatMap(b => Console.printLine(b.toString))
        .catchAll(e => Console.printLine(e.toString))
      _ <- ZIO
        .fromEither(barStr2.fromJson[Foo])
        .flatMap(b => Console.printLine(b.toString))
        .catchAll(e => Console.printLine(e.toString))
    yield ()
}

Output:

{"bar":42}
{"bar":42,"type":"BarOk"}
(missing hint 'type')
BarOk(42)

Expected output:

{"bar":42,"type":"BarNotOk"}
{"bar":42,"type":"BarOk"}
BarNotOk(42)
BarOk(42)
@fsvehla fsvehla added the good first issue Good for newcomers label Dec 17, 2024
@EvgeniyNorin
Copy link

EvgeniyNorin commented Dec 19, 2024

Seems like i found out the reason. Let me take it

@EvgeniyNorin
Copy link

@fsvehla i think #1112 closes this issue

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

No branches or pull requests

3 participants