diff --git a/zio-json/shared/src/main/scala/zio/json/JsonFieldDecoder.scala b/zio-json/shared/src/main/scala/zio/json/JsonFieldDecoder.scala index 68fc213c..3d3201de 100644 --- a/zio-json/shared/src/main/scala/zio/json/JsonFieldDecoder.scala +++ b/zio-json/shared/src/main/scala/zio/json/JsonFieldDecoder.scala @@ -40,7 +40,7 @@ trait JsonFieldDecoder[+A] { def unsafeDecodeField(trace: List[JsonError], in: String): A } -object JsonFieldDecoder { +object JsonFieldDecoder extends LowPriorityJsonFieldDecoder { def apply[A](implicit a: JsonFieldDecoder[A]): JsonFieldDecoder[A] = a implicit val string: JsonFieldDecoder[String] = new JsonFieldDecoder[String] { @@ -65,3 +65,13 @@ object JsonFieldDecoder { } } } + +private[json] trait LowPriorityJsonFieldDecoder { + + def string: JsonFieldDecoder[String] + + private def quotedString = string.map(raw => s""""$raw"""") + + implicit def stringLike[T <: String: JsonDecoder]: JsonFieldDecoder[T] = + quotedString.mapOrFail(implicitly[JsonDecoder[T]].decodeJson) +} diff --git a/zio-json/shared/src/test/scala-3/zio/json/DerivedDecoderSpec.scala b/zio-json/shared/src/test/scala-3/zio/json/DerivedDecoderSpec.scala index b7b6379f..46a5c05a 100644 --- a/zio-json/shared/src/test/scala-3/zio/json/DerivedDecoderSpec.scala +++ b/zio-json/shared/src/test/scala-3/zio/json/DerivedDecoderSpec.scala @@ -51,6 +51,12 @@ object DerivedDecoderSpec extends ZIOSpecDefault { assertTrue("""{"aOrB": "A", "optA": "A"}""".fromJson[Foo] == Right(Foo("A", Some("A")))) && assertTrue("""{"aOrB": "C"}""".fromJson[Foo] == Left(".aOrB(expected one of: A, B)")) - } + }, + test("Derives and decodes for a custom map key string-based union type") { + case class Foo(aOrB: Map["A" | "B", Int]) derives JsonDecoder + + assertTrue("""{"aOrB": {"A": 1, "B": 2}}""".fromJson[Foo] == Right(Foo(Map("A" -> 1, "B" -> 2)))) && + assertTrue("""{"aOrB": {"C": 1}}""".fromJson[Foo] == Left(".aOrB.C((expected one of: A, B))")) + }, ) } diff --git a/zio-json/shared/src/test/scala-3/zio/json/DerivedEncoderSpec.scala b/zio-json/shared/src/test/scala-3/zio/json/DerivedEncoderSpec.scala index 2eb329c4..2c21a599 100644 --- a/zio-json/shared/src/test/scala-3/zio/json/DerivedEncoderSpec.scala +++ b/zio-json/shared/src/test/scala-3/zio/json/DerivedEncoderSpec.scala @@ -49,6 +49,11 @@ object DerivedEncoderSpec extends ZIOSpecDefault { case class Foo(aOrB: "A" | "B", optA: Option["A"]) derives JsonEncoder assertTrue(Foo("A", Some("A")).toJson == """{"aOrB":"A","optA":"A"}""") + }, + test("Derives and encodes for a custom map key string-based union type") { + case class Foo(aOrB: Map["A" | "B", Int]) derives JsonEncoder + + assertTrue(Foo(Map("A" -> 1, "B" -> 2)).toJson == """{"aOrB":{"A":1,"B":2}}""") } ) }