circe / circe

Yet another JSON library for Scala

Home Page:https://circe.github.io/circe/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Inconsistent encoding/decoding of nested sum types

matil019 opened this issue · comments

As of 0.14.5, derived encoder and decoder of a nested sum type are inconsistent. The Decoder can't decode a JSON encoded by the Encoder.

Minimal example:

import io.circe.Decoder
import io.circe.Encoder
import io.circe.generic.semiauto.deriveDecoder
import io.circe.generic.semiauto.deriveEncoder
import io.circe.parser.decode
import io.circe.syntax._

sealed trait Top

object Top {
  sealed trait Middle extends Top

  object Middle {
    case object Bottom extends Middle
  }

  implicit val decodeTop: Decoder[Top] = deriveDecoder
  implicit val encodeTop: Encoder[Top] = deriveEncoder
}

object Main {
  def main(args: Array[String]): Unit = {
    val s = (Top.Middle.Bottom: Top).asJson.noSpaces
    println(s)
    println(decode[Top](s))
  }
}

Expected output (scala:3.2.2, circe:0.14.3)

{"Middle":{"Bottom":{}}}
Right(Bottom)

Actual output (scala:3.2.2, circe:0.14.5)

{"Middle":{"Bottom":{}}}
Left(DecodingFailure at .Middle: type Top has no class/object/case named 'Middle'.)

^ In this case, the decoder can decode {"Bottom":{}} to Bottom.


It turned out that both of the above are also inconsistent with scala 2.13 build of circe:

Output (scala:2.13.0, circe:0.14.3/0.14.5)

{"Bottom":{}}
Right(Bottom)

So I'm not sure which encoding is correct.

I would expect the Scala 2 output, not the Scala 3 output.

Seems like this relates to / was introduced by #2098 (I didn't look into the code changes (yet), but did test before / after that commit).

Found a fix for the inconsistency.

(I do agree that the encoded json should be the same as for Scala 2, but fixing that is beyond what I'm currently able to contribute.)

(I do agree that the encoded json should be the same as for Scala 2, but fixing that is beyond what I'm currently able to contribute.)

Nevermind - found a better way to fix the inconsistency that also fixes the encoding to {"Bottom":{}}.