plokhotnyuk / jsoniter-scala

Scala macros for compile-time generation of safe and ultra-fast JSON codecs + circe booster
MIT License
746 stars 100 forks source link

store generated codecs as source in src_managed #1122

Open domdorn opened 8 months ago

domdorn commented 8 months ago

Hi,

at the moment, jsoniter-scala doesn't store the generated macro code. Debugging using

implicit val printCodec: CodecMakerConfig.PrintCodec = new CodecMakerConfig.PrintCodec {}

is hard as this gets printed everywhere the codec is used. It would be way easier to debug codec issues, if jsoniter-scala would simply put the generated code in e.g. target/src_managed/ or some place similar and I could simply open that file with my IDE and see the generated code.

Is this possible somehow?

Thanks, Dominik

plokhotnyuk commented 8 months ago

Hi Dominik,

I don't know yet if it possible to generate source files from macros in a way that is suitable for debugging.

Have you tried to limit a scope where implicit val printCodec: CodecMakerConfig.PrintCodec is defined?

As example for some nested data structure you can define that implicit value only for a codec of some sub-structure:


case class Nested(s: String)
case class TopLevel(nested: Nested)

implicit val topLevelCodec: JsonValueCodec[TopLevel] = {
  implicit val nestedCodec: JsonValueCodec[Nested] = {
    implicit val printCodec: CodecMakerConfig.PrintCodec = new CodecMakerConfig.PrintCodec {}
    JsonCodecMaker.make[Nested]
  }

  JsonCodecMaker.make[TopLevel]
}

Also, I'm interested about a context to understand why debugging of generated codecs is required and just unit testing is not enough to solve your issue.

domdorn commented 8 months ago

as for context, one example: We have a case class Timestamp(value: Long) class that in some services / for some calls has to be serialized as millis-since-epoch, in others as ISO-String. We have two codecs for the corresponding serialization. If we forget to bring the right codec in scope, the timestamp gets serialized as an object {"value": 1234..} which is the worst encoding/unwanted. We usually define most of the codecs in a object JsonSupport { ... } .. sometimes its necessary to see which codec is actually used or if jsoniter-scala even creates a new codec cause non of the existing ones is in scope.

The workaround with scoping you shared in the last comment definetly will make it easier to debug issues, thanks!

e.g.:


case class Sample(t: Timestamp)

one encoding:

{"t": 1709038343000}

other encoding:

{"t": "2024-02-27T13:52:27.000Z"}

encoding if we forget to put the right codec in scope (unwanted):

{"t": { "value": 1709038343000 }}