plokhotnyuk / jsoniter-scala

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

Add an option for turning off injection of custom codecs using implicits #333

Open plokhotnyuk opened 5 years ago

plokhotnyuk commented 5 years ago

This issue is created on behalf of @pityka for cases when the same type is used for different codecs generated by the make call.

Here is an example of a case code generation for sum of types when some its leaf type have an implicitly defined codec:

{
    import com.github.plokhotnyuk.jsoniter_scala.core._
    import com.github.plokhotnyuk.jsoniter_scala.macros._
    sealed trait P
    case class Leaf1(a: String) extends P
    case class Leaf2(a: Int) extends P

    object Codecs {

      implicit val pCodec: JsonValueCodec[P] =
        JsonCodecMaker.make[P](CodecMakerConfig())

      // test passes if this is removed
      implicit val leaf1Codec: JsonValueCodec[Leaf1] =
        JsonCodecMaker.make[Leaf1](CodecMakerConfig())

    }
    import Codecs._

    println(readFromString[P](writeToString[P]((Leaf1("a")))))
  }

W/A would be: 1) Do not use implicit keyword for leaf1Codec definition. 2) Split codec derivation to different namespace, like here:

{
    import com.github.plokhotnyuk.jsoniter_scala.core._
    import com.github.plokhotnyuk.jsoniter_scala.macros._
    sealed trait P
    case class Leaf1(a: String) extends P
    case class Leaf2(a: Int) extends P

    object Codec1 {
      implicit val leaf1Codec: JsonValueCodec[Leaf1] =
        JsonCodecMaker.make[Leaf1](CodecMakerConfig())
    }

    object Codec2 {

      implicit val pCodec: JsonValueCodec[P] =
        JsonCodecMaker.make[P](CodecMakerConfig())

    }

    import Codec1._
    import Codec2._

    println(readFromString[P](writeToString[P]((Leaf1("a")))))
    println(readFromString[Leaf1](writeToString[Leaf1]((Leaf1("a")))))
  }
pityka commented 5 years ago

Hello! Thank you for creating the issue.

I found an other strange behaviour related to the injection of codecs from implicits. In this case the decoder threw an NullPointerException. I created a minimal reproducer project at https://github.com/pityka/report-npe . sbt run will run a test and (on my side) throws an NPE. Removing the implicit keyword on line https://github.com/pityka/report-npe/blob/master/src/main/scala/types.scala#L8 solves the NPE.

plokhotnyuk commented 5 years ago

Here is a placeholder issue which currently gathering requirements for new derivation API. One key idea is about refactoring in such way that injection of codecs can be done without using of impicits.