Search code examples
scalascala-3circe

Pascal case transform for discriminator parsing to enum cases


I have the following JSON:

[{"type": "first_variant", ...}, {"type": "second_variant", ...}]

And I want to parse this JSON to an array of Variant enums like this:

enum Variant:
  case FirstVariant(...)
  case SecondVariant(...)

How can I do it with circe?


Solution

  • In Scala 3 and Circe 0.14.6, you can require a discriminator field in snake case by providing the appropriate Configuration and Codec:

    //> using lib io.circe::circe-core:0.14.6
    //> using lib io.circe::circe-generic:0.14.6
    
    import io.circe.Codec
    import io.circe.syntax.EncoderOps
    import io.circe.derivation.Configuration
    import io.circe.generic.auto.given
    
    enum Variant:
      case FirstVariant(x: Int)
      case SecondVariant(y: String)
    
    given Configuration =
      Configuration
        .default
        .withDiscriminator("type")
        .withSnakeCaseConstructorNames
    
    given Codec[Variant] =
      Codec.AsObject.derivedConfigured
    
    @main def example =
      val l = List(
        Variant.FirstVariant(1),
        Variant.SecondVariant("hello")
      )
      val lJson = l.asJson
      println(lJson)
      val l2 = lJson.as[List[Variant]].toOption.get
      assert(l2 == l)
    

    This outputs:

    [
      {
        "x" : 1,
        "type" : "first_variant"
      },
      {
        "y" : "hello",
        "type" : "second_variant"
      }
    ]
    

    References: I derived this example from the (outdated) Circle documentation on ADTs, the answer to a similar question for Circe 0.7.0 and the source code of Circe 0.14.6 (Configuration.scala and ConfiguredDerivesSuite.scala).