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

Optional type discriminator #286

Open
nryanov opened this issue May 3, 2021 · 1 comment
Open

Optional type discriminator #286

nryanov opened this issue May 3, 2021 · 1 comment

Comments

@nryanov
Copy link

nryanov commented May 3, 2021

Hello!

I have a domain model (for consul api) and want to encode/decode types like Check and ServiceCheck and their subtypes . The issue is in model encoding/decoding results. Classes :

sealed trait Check
final case class ScriptCheck(...) extends Check
final case class HttpCheck(...) extends Check
final case class TCPCheck(...) extends Check
final case class TTLCheck(...) extends Check
final case class DockerCheck(...) extends Check
final case class GRpcCheck(...) extends Check
final case class AliasCheck(...) extends Check

and encoders/decoders:

implicit val checkEncoder: JsonEncoder[Check] = DeriveJsonEncoder.gen[Check]
implicit val checkDecoder: JsonDecoder[Check] = DeriveJsonDecoder.gen[Check]

When i encode instance of any subtype of Check or ServiceCheck i get a json object like this:

{ 
    "ScriptCheck": {...}
}

The api does not recognise field ScriptCheck and fails with an error. If i try to encode ScriptCheck explicitly using encoder for ScriptCheck type then json will not have type discriminator.

I tried to use annotations with empty values @jsonHint("") and @jsonDiscriminator(""), as i thought that it will remove it because in macros there is a code like this:

def discrim = ctx.annotations.collectFirst { case jsonDiscriminator(n) => n }
    if (discrim.isEmpty) {...} else {...}

but got an error:

Caused by: java.lang.IllegalArgumentException: requirement failed
	at scala.Predef$.require(Predef.scala:325)
	at zio.json.internal.StringMatrix.<init>(lexer.scala:393)
	at zio.json.DeriveJsonDecoder$$anon$4.<init>(macros.scala:251)
	at zio.json.DeriveJsonDecoder$.dispatch(macros.scala:249)

Also, i tried to construct encoder using eitherWith, but in result i get a json with additional field Left or Right.
In the meantime, decoder can be constructed using orElse and it will not require type discriminator.

Is it possible to completely remove type discriminator?

@murrelljenna
Copy link

murrelljenna commented Sep 9, 2022

Hi! I had the same problem of this and ended up doing this:

val scriptCheckEncoder = DeriveJsonEncoder.Gen[ScriptCheck]
// ... repeat for all your types

implicit val checkEncoder: JsonEncoder[Check] = DeriveJsonEncoder.gen[Check].contramap(¨
  {
    case c:ScriptCheck => c
    // Repeat for all your types
  }
)

This seems silly, but what this is essentially doing is telling the type system to look for your implicitly defined case class encoders and use those instead of the ADT encoder.

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