Skip to content

Commit

Permalink
fix to ast name transform (#813)
Browse files Browse the repository at this point in the history
  • Loading branch information
senia-psm authored Dec 5, 2022
1 parent 88e204f commit 8cbd5fb
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 71 deletions.
2 changes: 1 addition & 1 deletion zio-json/shared/src/main/scala-2.x/zio/json/macros.scala
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ object DeriveJsonEncoder {
.foldLeft[Either[String, Chunk[(String, Json)]]](Right(Chunk.empty)) { case (c, param) =>
val name = param.annotations.collectFirst { case jsonField(name) =>
name
}.getOrElse(param.label)
}.getOrElse(nameTransform(param.label))
c.flatMap { chunk =>
param.typeclass.toJsonAST(param.dereference(a)).map { value =>
if (value == Json.Null) chunk
Expand Down
2 changes: 1 addition & 1 deletion zio-json/shared/src/main/scala-3/zio/json/macros.scala
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ object DeriveJsonEncoder extends Derivation[JsonEncoder] { self =>
.foldLeft[Either[String, Chunk[(String, Json)]]](Right(Chunk.empty)) { case (c, param) =>
val name = param.annotations.collectFirst { case jsonField(name) =>
name
}.getOrElse(param.label)
}.getOrElse(nameTransform(param.label))
c.flatMap { chunk =>
param.typeclass.toJsonAST(param.deref(a)).map { value =>
if (value == Json.Null) chunk
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package zio.json

import zio.json.JsonCodecConfiguration.SumTypeHandling.DiscriminatorField
import zio.json.ast.Json
import zio.test._

object ConfigurableDeriveCodecSpec extends ZIOSpecDefault {
Expand All @@ -15,77 +16,154 @@ object ConfigurableDeriveCodecSpec extends ZIOSpecDefault {

def spec = suite("ConfigurableDeriveCodecSpec")(
suite("defaults")(
test("should not map field names by default") {
val expectedStr = """{"someField":1,"someOtherField":"a"}"""
val expectedObj = ClassWithFields(1, "a")

implicit val codec: JsonCodec[ClassWithFields] = DeriveJsonCodec.gen

assertTrue(
expectedStr.fromJson[ClassWithFields].toOption.get == expectedObj,
expectedObj.toJson == expectedStr
)
},
test("should not use discriminator by default") {
val expectedStr = """{"CaseObj":{}}"""
val expectedObj: ST = ST.CaseObj

implicit val codec: JsonCodec[ST] = DeriveJsonCodec.gen

assertTrue(
expectedStr.fromJson[ST].toOption.get == expectedObj,
expectedObj.toJson == expectedStr
)
},
test("should allow extra fields by default") {
val jsonStr = """{"someField":1,"someOtherField":"a","extra":123}"""
val expectedObj = ClassWithFields(1, "a")

implicit val codec: JsonCodec[ClassWithFields] = DeriveJsonCodec.gen

assertTrue(
jsonStr.fromJson[ClassWithFields].toOption.get == expectedObj
)
}
suite("string")(
test("should not map field names by default") {
val expectedStr = """{"someField":1,"someOtherField":"a"}"""
val expectedObj = ClassWithFields(1, "a")

implicit val codec: JsonCodec[ClassWithFields] = DeriveJsonCodec.gen

assertTrue(
expectedStr.fromJson[ClassWithFields].toOption.get == expectedObj,
expectedObj.toJson == expectedStr
)
},
test("should not use discriminator by default") {
val expectedStr = """{"CaseObj":{}}"""
val expectedObj: ST = ST.CaseObj

implicit val codec: JsonCodec[ST] = DeriveJsonCodec.gen

assertTrue(
expectedStr.fromJson[ST].toOption.get == expectedObj,
expectedObj.toJson == expectedStr
)
},
test("should allow extra fields by default") {
val jsonStr = """{"someField":1,"someOtherField":"a","extra":123}"""
val expectedObj = ClassWithFields(1, "a")

implicit val codec: JsonCodec[ClassWithFields] = DeriveJsonCodec.gen

assertTrue(
jsonStr.fromJson[ClassWithFields].toOption.get == expectedObj
)
}
),
suite("AST")(
test("should not map field names by default") {
val expectedAST = Json.Obj("someField" -> Json.Num(1), "someOtherField" -> Json.Str("a"))
val expectedObj = ClassWithFields(1, "a")

implicit val codec: JsonCodec[ClassWithFields] = DeriveJsonCodec.gen

assertTrue(
expectedAST.as[ClassWithFields].toOption.get == expectedObj,
expectedObj.toJsonAST.toOption.get == expectedAST
)
},
test("should not use discriminator by default") {
val expectedAST = Json.Obj("CaseObj" -> Json.Obj())
val expectedObj: ST = ST.CaseObj

implicit val codec: JsonCodec[ST] = DeriveJsonCodec.gen

assertTrue(
expectedAST.as[ST].toOption.get == expectedObj,
expectedObj.toJsonAST.toOption.get == expectedAST
)
},
test("should allow extra fields by default") {
val jsonAST = Json.Obj("someField" -> Json.Num(1), "someOtherField" -> Json.Str("a"), "extra" -> Json.Num(1))
val expectedObj = ClassWithFields(1, "a")

implicit val codec: JsonCodec[ClassWithFields] = DeriveJsonCodec.gen

assertTrue(
jsonAST.as[ClassWithFields].toOption.get == expectedObj
)
}
)
),
suite("overrides")(
test("should override field name mapping") {
val expectedStr = """{"some_field":1,"some_other_field":"a"}"""
val expectedObj = ClassWithFields(1, "a")

implicit val config: JsonCodecConfiguration =
JsonCodecConfiguration(fieldNameMapping = SnakeCase)
implicit val codec: JsonCodec[ClassWithFields] = DeriveJsonCodec.gen

assertTrue(
expectedStr.fromJson[ClassWithFields].toOption.get == expectedObj,
expectedObj.toJson == expectedStr
)
},
test("should specify discriminator") {
val expectedStr = """{"$type":"CaseClass","i":1}"""
val expectedObj: ST = ST.CaseClass(i = 1)

implicit val config: JsonCodecConfiguration =
JsonCodecConfiguration(sumTypeHandling = DiscriminatorField("$type"))
implicit val codec: JsonCodec[ST] = DeriveJsonCodec.gen

assertTrue(
expectedStr.fromJson[ST].toOption.get == expectedObj,
expectedObj.toJson == expectedStr
)
},
test("should prevent extra fields") {
val jsonStr = """{"someField":1,"someOtherField":"a","extra":123}"""

implicit val config: JsonCodecConfiguration =
JsonCodecConfiguration(allowExtraFields = false)
implicit val codec: JsonCodec[ClassWithFields] = DeriveJsonCodec.gen

assertTrue(
jsonStr.fromJson[ClassWithFields].isLeft
)
}
suite("string")(
test("should override field name mapping") {
val expectedStr = """{"some_field":1,"some_other_field":"a"}"""
val expectedObj = ClassWithFields(1, "a")

implicit val config: JsonCodecConfiguration =
JsonCodecConfiguration(fieldNameMapping = SnakeCase)
implicit val codec: JsonCodec[ClassWithFields] = DeriveJsonCodec.gen

assertTrue(
expectedStr.fromJson[ClassWithFields].toOption.get == expectedObj,
expectedObj.toJson == expectedStr
)
},
test("should specify discriminator") {
val expectedStr = """{"$type":"CaseClass","i":1}"""
val expectedObj: ST = ST.CaseClass(i = 1)

implicit val config: JsonCodecConfiguration =
JsonCodecConfiguration(sumTypeHandling = DiscriminatorField("$type"))
implicit val codec: JsonCodec[ST] = DeriveJsonCodec.gen

assertTrue(
expectedStr.fromJson[ST].toOption.get == expectedObj,
expectedObj.toJson == expectedStr
)
},
test("should prevent extra fields") {
val jsonStr = """{"someField":1,"someOtherField":"a","extra":123}"""

implicit val config: JsonCodecConfiguration =
JsonCodecConfiguration(allowExtraFields = false)
implicit val codec: JsonCodec[ClassWithFields] = DeriveJsonCodec.gen

assertTrue(
jsonStr.fromJson[ClassWithFields].isLeft
)
}
),
suite("AST")(
test("should override field name mapping") {
val expectedAST = Json.Obj("some_field" -> Json.Num(1), "some_other_field" -> Json.Str("a"))
val expectedObj = ClassWithFields(1, "a")

implicit val config: JsonCodecConfiguration =
JsonCodecConfiguration(fieldNameMapping = SnakeCase)
implicit val codec: JsonCodec[ClassWithFields] = DeriveJsonCodec.gen

assertTrue(
expectedAST.as[ClassWithFields].toOption.get == expectedObj,
expectedObj.toJsonAST.toOption.get == expectedAST
)
},
test("should specify discriminator") {
val expectedAST = Json.Obj("$type" -> Json.Str("CaseClass"), "i" -> Json.Num(1))
val expectedObj: ST = ST.CaseClass(i = 1)

implicit val config: JsonCodecConfiguration =
JsonCodecConfiguration(sumTypeHandling = DiscriminatorField("$type"))
implicit val codec: JsonCodec[ST] = DeriveJsonCodec.gen

assertTrue(
expectedAST.as[ST].toOption.get == expectedObj,
expectedObj.toJsonAST.toOption.get == expectedAST
)
},
test("should prevent extra fields") {
val jsonAST = Json.Obj("someField" -> Json.Num(1), "someOtherField" -> Json.Str("a"), "extra" -> Json.Num(1))

implicit val config: JsonCodecConfiguration =
JsonCodecConfiguration(allowExtraFields = false)
implicit val codec: JsonCodec[ClassWithFields] = DeriveJsonCodec.gen

assertTrue(
jsonAST.as[ClassWithFields].isLeft
)
}
)
)
)
}
6 changes: 6 additions & 0 deletions zio-json/shared/src/test/scala/zio/json/CodecSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package testzio.json

import zio._
import zio.json._
import zio.json.ast.Json
import zio.test.Assertion._
import zio.test._

Expand Down Expand Up @@ -96,10 +97,15 @@ object CodecSpec extends ZIOSpecDefault {
assert(indianaJones.fromJson[Custom])(isRight(equalTo(Custom("")))) &&
assert(overrides.fromJson[OverridesAlsoWork])(isRight(equalTo(OverridesAlsoWork("", 0)))) &&
assertTrue(Kebabed("").toJson == kebabed) &&
assertTrue(Kebabed("").toJsonAST.toOption.get == kebabed.fromJson[Json].toOption.get) &&
assertTrue(Snaked("").toJson == snaked) &&
assertTrue(Snaked("").toJsonAST.toOption.get == snaked.fromJson[Json].toOption.get) &&
assertTrue(Pascaled("").toJson == pascaled) &&
assertTrue(Pascaled("").toJsonAST.toOption.get == pascaled.fromJson[Json].toOption.get) &&
assertTrue(Cameled("").toJson == cameled) &&
assertTrue(Cameled("").toJsonAST.toOption.get == cameled.fromJson[Json].toOption.get) &&
assertTrue(Custom("").toJson == indianaJones) &&
assertTrue(Custom("").toJsonAST.toOption.get == indianaJones.fromJson[Json].toOption.get) &&
assertTrue(OverridesAlsoWork("", 0).toJson == overrides)
},
test("unicode") {
Expand Down

0 comments on commit 8cbd5fb

Please sign in to comment.