From 71cb585e31c146da00455c7a0bb7ebe9def1a3e1 Mon Sep 17 00:00:00 2001 From: David Anyatonwu Date: Sat, 8 Jun 2024 22:28:30 +0000 Subject: [PATCH 1/4] fix: handle missing collection fields in JSON decoding --- .../schema/example/example1/Example1.scala | 19 +- .../schema/example/example2/Example2.scala | 10 +- .../schema/example/example3/Example3.scala | 10 +- .../scala/zio/schema/codec/JsonCodec.scala | 257 ++++++++++++------ .../zio/schema/codec/JsonCodecSpec.scala | 22 +- 5 files changed, 208 insertions(+), 110 deletions(-) diff --git a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example1/Example1.scala b/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example1/Example1.scala index c2df72747..22c33e5c6 100644 --- a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example1/Example1.scala +++ b/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example1/Example1.scala @@ -3,6 +3,7 @@ package dev.zio.schema.example.example1 import zio._ import zio.schema.{ DeriveSchema, Schema, TypeId } import zio.stream.ZPipeline +import zio.schema.codec.JsonCodec /** * Example 1 of ZIO-Schema: @@ -129,6 +130,7 @@ object MacroConstruction { implicit val schemaPerson: Schema[Person] = DeriveSchema.gen[Person] + val schemaPaymentMethod: Schema[PaymentMethod] = DeriveSchema.gen[PaymentMethod] val schemaCustomer: Schema[Customer] = DeriveSchema.gen[Customer] @@ -142,13 +144,15 @@ object JsonSample extends zio.ZIOAppDefault { import ManualConstruction._ import zio.schema.codec.JsonCodec import zio.stream.ZStream + implicit val defaultConfig: JsonCodec.Config = JsonCodec.Config.default + override def run: ZIO[Environment with ZIOAppArgs, Any, Any] = for { _ <- ZIO.unit person = Person("Michelle", 32) personToJsonTransducer = JsonCodec - .schemaBasedBinaryCodec[Person](schemaPerson) + .schemaBasedBinaryCodec[Person](schemaPerson, defaultConfig) .streamEncoder _ <- ZStream(person) .via(personToJsonTransducer) @@ -187,6 +191,9 @@ object CombiningExample extends ZIOAppDefault { import ManualConstruction._ import zio.schema.codec.{ JsonCodec, ProtobufCodec } import zio.stream.ZStream + implicit val defaultConfig: JsonCodec.Config = JsonCodec.Config.default + + override def run: ZIO[Environment with ZIOAppArgs, Any, Any] = for { @@ -194,8 +201,8 @@ object CombiningExample extends ZIOAppDefault { _ <- ZIO.debug("combining roundtrip") person = Person("Michelle", 32) - personToJson = JsonCodec.schemaBasedBinaryCodec[Person](schemaPerson).streamEncoder - jsonToPerson = JsonCodec.schemaBasedBinaryCodec[Person](schemaPerson).streamDecoder + personToJson = JsonCodec.schemaBasedBinaryCodec[Person](schemaPerson, defaultConfig).streamEncoder + jsonToPerson = JsonCodec.schemaBasedBinaryCodec[Person](schemaPerson, defaultConfig).streamDecoder personToProto = ProtobufCodec.protobufCodec[Person](schemaPerson).streamEncoder protoToPerson = ProtobufCodec.protobufCodec[Person](schemaPerson).streamDecoder @@ -222,6 +229,8 @@ object DictionaryExample extends ZIOAppDefault { import MacroConstruction._ import zio.schema.codec.JsonCodec import zio.stream.ZStream + implicit val defaultConfig: JsonCodec.Config = JsonCodec.Config.default + override def run: ZIO[Environment with ZIOAppArgs, Any, Any] = for { _ <- ZIO.unit @@ -229,12 +238,12 @@ object DictionaryExample extends ZIOAppDefault { dictionary = Map("m" -> person) dictionaryToJson = JsonCodec .schemaBasedBinaryCodec[scala.collection.immutable.Map[String, Person]]( - schemaPersonDictionaryFromMacro + schemaPersonDictionaryFromMacro, defaultConfig ) .streamEncoder jsonToDictionary = JsonCodec .schemaBasedBinaryCodec[scala.collection.immutable.Map[String, Person]]( - schemaPersonDictionaryFromMacro + schemaPersonDictionaryFromMacro, defaultConfig ) .streamDecoder newPersonDictionary <- ZStream(dictionary) diff --git a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example2/Example2.scala b/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example2/Example2.scala index 83a664e65..b2f93d872 100644 --- a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example2/Example2.scala +++ b/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example2/Example2.scala @@ -153,13 +153,15 @@ import dev.zio.schema.example.example2.Domain._ object JsonSample extends zio.ZIOAppDefault { import zio.schema.codec.JsonCodec import zio.stream.ZStream + implicit val defaultConfig: JsonCodec.Config = JsonCodec.Config.default + override def run: ZIO[Environment with ZIOAppArgs, Any, Any] = for { _ <- ZIO.unit person = Person("Michelle", 32) personToJsonPipeline = JsonCodec - .schemaBasedBinaryCodec[Person](Person.schema) + .schemaBasedBinaryCodec[Person](Person.schema, defaultConfig) .streamEncoder _ <- ZStream(person) .via(personToJsonPipeline) @@ -196,6 +198,8 @@ object ProtobufExample extends ZIOAppDefault { object CombiningExample extends zio.ZIOAppDefault { import zio.schema.codec.{ JsonCodec, ProtobufCodec } import zio.stream.ZStream + implicit val defaultConfig: JsonCodec.Config = JsonCodec.Config.default + override def run: ZIO[Environment with ZIOAppArgs, Any, Any] = for { @@ -203,8 +207,8 @@ object CombiningExample extends zio.ZIOAppDefault { _ <- ZIO.debug("combining roundtrip") person = Person("Michelle", 32) - personToJson = JsonCodec.schemaBasedBinaryCodec[Person](Person.schema).streamEncoder - jsonToPerson = JsonCodec.schemaBasedBinaryCodec[Person](Person.schema).streamDecoder + personToJson = JsonCodec.schemaBasedBinaryCodec[Person](Person.schema, defaultConfig).streamEncoder + jsonToPerson = JsonCodec.schemaBasedBinaryCodec[Person](Person.schema, defaultConfig).streamDecoder personToProto = ProtobufCodec.protobufCodec[Person](Person.schema).streamEncoder protoToPerson = ProtobufCodec.protobufCodec[Person](Person.schema).streamDecoder diff --git a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example3/Example3.scala b/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example3/Example3.scala index 164f3f614..1def541a3 100644 --- a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example3/Example3.scala +++ b/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example3/Example3.scala @@ -57,6 +57,8 @@ private[example3] object Domain { object Example3 extends ZIOAppDefault { import dev.zio.schema.example.example3.Domain._ import zio.schema.codec.JsonCodec + implicit val defaultConfig: JsonCodec.Config = JsonCodec.Config.default + val personTransformation: Schema[Person] = PersonDTO.schema.transform[Person]( (dto: PersonDTO) => Person(dto.firstname + " " + dto.lastname, dto.years), @@ -74,20 +76,20 @@ object Example3 extends ZIOAppDefault { // get objects from JSON personDTO <- ZIO.fromEither( - JsonCodec.schemaBasedBinaryCodec[PersonDTO](PersonDTO.schema).decode(chunks) + JsonCodec.schemaBasedBinaryCodec[PersonDTO](PersonDTO.schema, defaultConfig).decode(chunks) ) person <- ZIO.fromEither( - JsonCodec.schemaBasedBinaryCodec[Person](personTransformation).decode(chunks) + JsonCodec.schemaBasedBinaryCodec[Person](personTransformation, defaultConfig).decode(chunks) ) _ <- ZIO.debug("PersonDTO : " + personDTO) _ <- ZIO.debug("Person : " + person) // get JSON from Objects personJson = new String( - JsonCodec.schemaBasedBinaryCodec[Person](Person.schema).encode(person).toArray + JsonCodec.schemaBasedBinaryCodec[Person](Person.schema, defaultConfig).encode(person).toArray ) personDTOJson = new String( - JsonCodec.schemaBasedBinaryCodec[Person](personTransformation).encode(person).toArray + JsonCodec.schemaBasedBinaryCodec[Person](personTransformation, defaultConfig).encode(person).toArray ) _ <- ZIO.debug("Person JSON: " + personJson) _ <- ZIO.debug("PersonDTO JSON: " + personDTOJson) diff --git a/zio-schema-json/shared/src/main/scala/zio/schema/codec/JsonCodec.scala b/zio-schema-json/shared/src/main/scala/zio/schema/codec/JsonCodec.scala index 73cdac35b..61208ff0d 100644 --- a/zio-schema-json/shared/src/main/scala/zio/schema/codec/JsonCodec.scala +++ b/zio-schema-json/shared/src/main/scala/zio/schema/codec/JsonCodec.scala @@ -66,10 +66,10 @@ object JsonCodec { ) } - implicit def schemaBasedBinaryCodec[A](implicit schema: Schema[A]): BinaryCodec[A] = + implicit def schemaBasedBinaryCodec[A](implicit schema: Schema[A], config: JsonCodec.Config): BinaryCodec[A] = schemaBasedBinaryCodec[A](JsonCodec.Config.default) - def schemaBasedBinaryCodec[A](cfg: Config)(implicit schema: Schema[A]): BinaryCodec[A] = + def schemaBasedBinaryCodec[A](cfg: Config)(implicit schema: Schema[A], config: JsonCodec.Config): BinaryCodec[A] = new BinaryCodec[A] { override def decode(whole: Chunk[Byte]): Either[DecodeError, A] = JsonDecoder.decode( @@ -104,13 +104,13 @@ object JsonCodec { def jsonEncoder[A](cfg: JsonCodec.Config)(schema: Schema[A]): ZJsonEncoder[A] = JsonEncoder.schemaEncoder(schema, cfg) - def jsonDecoder[A](schema: Schema[A]): ZJsonDecoder[A] = + def jsonDecoder[A](schema: Schema[A])(implicit config: JsonCodec.Config): ZJsonDecoder[A] = JsonDecoder.schemaDecoder(schema) - def jsonCodec[A](schema: Schema[A]): ZJsonCodec[A] = + def jsonCodec[A](schema: Schema[A])(implicit config: JsonCodec.Config): ZJsonCodec[A] = ZJsonCodec(jsonEncoder(schema), jsonDecoder(schema)) - def jsonCodec[A](cfg: JsonCodec.Config)(schema: Schema[A]): ZJsonCodec[A] = + def jsonCodec[A](cfg: JsonCodec.Config)(schema: Schema[A])(implicit config: JsonCodec.Config): ZJsonCodec[A] = ZJsonCodec(jsonEncoder(cfg)(schema), jsonDecoder(schema)) object Codecs { @@ -490,7 +490,7 @@ object JsonCodec { import Codecs._ import ProductDecoder._ - final def decode[A](schema: Schema[A], json: String): Either[DecodeError, A] = + final def decode[A](schema: Schema[A], json: String)(implicit config: JsonCodec.Config): Either[DecodeError, A] = schemaDecoder(schema).decodeJson(json) match { case Left(value) => Left(ReadError(Cause.empty, value)) case Right(value) => Right(value) @@ -537,7 +537,7 @@ object JsonCodec { } //scalafmt: { maxColumn = 400, optIn.configStyleArguments = false } - private[codec] def schemaDecoder[A](schema: Schema[A], discriminator: Int = -1): ZJsonDecoder[A] = schema match { + private[codec] def schemaDecoder[A](schema: Schema[A], discriminator: Int = -1)(implicit config: JsonCodec.Config): ZJsonDecoder[A] = schema match { case Schema.Primitive(standardType, _) => primitiveCodec(standardType).decoder case Schema.Optional(codec, _) => option(schemaDecoder(codec, discriminator)) case Schema.Tuple2(left, right, _) => ZJsonDecoder.tuple2(schemaDecoder(left, -1), schemaDecoder(right, -1)) @@ -633,7 +633,7 @@ object JsonCodec { private[codec] def mapDecoder[K, V]( ks: Schema[K], vs: Schema[V] - ): ZJsonDecoder[Map[K, V]] = { + )(implicit config: JsonCodec.Config): ZJsonDecoder[Map[K, V]] = { val valueDecoder = JsonDecoder.schemaDecoder(vs) jsonFieldDecoder(ks) match { case Some(jsonFieldDecoder) => @@ -656,7 +656,7 @@ object JsonCodec { case _ => None } - private def dynamicDecoder(schema: Schema.Dynamic): ZJsonDecoder[DynamicValue] = { + private def dynamicDecoder(schema: Schema.Dynamic)(implicit config: JsonCodec.Config): ZJsonDecoder[DynamicValue] = { val directMapping = schema.annotations.exists { case directDynamicMapping() => true case _ => false @@ -683,7 +683,7 @@ object JsonCodec { case Json.Null => DynamicValue.NoneValue } - private def enumDecoder[Z](parentSchema: Schema.Enum[Z], cases: Schema.Case[Z, _]*): ZJsonDecoder[Z] = { + private def enumDecoder[Z](parentSchema: Schema.Enum[Z], cases: Schema.Case[Z, _]*)(implicit config: JsonCodec.Config): ZJsonDecoder[Z] = { val caseNameAliases = cases.flatMap { case Schema.Case(name, _, _, _, _, annotations) => annotations.flatMap { @@ -801,7 +801,7 @@ object JsonCodec { private def deAliasCaseName(alias: String, caseNameAliases: Map[String, String]): String = caseNameAliases.getOrElse(alias, alias) - private def recordDecoder[Z](structure: Seq[Schema.Field[Z, _]]): ZJsonDecoder[ListMap[String, Any]] = { + private def recordDecoder[Z](structure: Seq[Schema.Field[Z, _]])(implicit config: JsonCodec.Config): ZJsonDecoder[ListMap[String, Any]] = { (trace: List[JsonError], in: RetractReader) => { val builder: ChunkBuilder[(String, Any)] = zio.ChunkBuilder.make[(String, Any)](structure.size) @@ -829,7 +829,7 @@ object JsonCodec { } } - private def fallbackDecoder[A, B](schema: Schema.Fallback[A, B]): ZJsonDecoder[Fallback[A, B]] = + private def fallbackDecoder[A, B](schema: Schema.Fallback[A, B])(implicit config: JsonCodec.Config): ZJsonDecoder[Fallback[A, B]] = new ZJsonDecoder[Fallback[A, B]] { def unsafeDecode(trace: List[JsonError], in: RetractReader): Fallback[A, B] = { @@ -977,28 +977,28 @@ object JsonCodec { schema.defaultConstruct() } - private[codec] def caseClass1Decoder[A, Z](discriminator: Int, schema: Schema.CaseClass1[A, Z]): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => + private[codec] def caseClass1Decoder[A, Z](discriminator: Int, schema: Schema.CaseClass1[A, Z])(implicit config: JsonCodec.Config): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => { val buffer: Array[Any] = unsafeDecodeFields(discriminator, trace, in, schema) schema.defaultConstruct(buffer(0).asInstanceOf[A]) } } - private[codec] def caseClass2Decoder[A1, A2, Z](discriminator: Int, schema: Schema.CaseClass2[A1, A2, Z]): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => + private[codec] def caseClass2Decoder[A1, A2, Z](discriminator: Int, schema: Schema.CaseClass2[A1, A2, Z])(implicit config: JsonCodec.Config): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => { val buffer: Array[Any] = unsafeDecodeFields(discriminator, trace, in, schema) schema.construct(buffer(0).asInstanceOf[A1], buffer(1).asInstanceOf[A2]) } } - private[codec] def caseClass3Decoder[A1, A2, A3, Z](discriminator: Int, schema: Schema.CaseClass3[A1, A2, A3, Z]): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => + private[codec] def caseClass3Decoder[A1, A2, A3, Z](discriminator: Int, schema: Schema.CaseClass3[A1, A2, A3, Z])(implicit config: JsonCodec.Config): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => { val buffer: Array[Any] = unsafeDecodeFields(discriminator, trace, in, schema) schema.construct(buffer(0).asInstanceOf[A1], buffer(1).asInstanceOf[A2], buffer(2).asInstanceOf[A3]) } } - private[codec] def caseClass4Decoder[A1, A2, A3, A4, Z](discriminator: Int, schema: Schema.CaseClass4[A1, A2, A3, A4, Z]): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => + private[codec] def caseClass4Decoder[A1, A2, A3, A4, Z](discriminator: Int, schema: Schema.CaseClass4[A1, A2, A3, A4, Z])(implicit config: JsonCodec.Config): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => { val buffer: Array[Any] = unsafeDecodeFields(discriminator, trace, in, schema) @@ -1006,7 +1006,7 @@ object JsonCodec { } } - private[codec] def caseClass5Decoder[A1, A2, A3, A4, A5, Z](discriminator: Int, schema: Schema.CaseClass5[A1, A2, A3, A4, A5, Z]): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => + private[codec] def caseClass5Decoder[A1, A2, A3, A4, A5, Z](discriminator: Int, schema: Schema.CaseClass5[A1, A2, A3, A4, A5, Z])(implicit config: JsonCodec.Config): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => { val buffer: Array[Any] = unsafeDecodeFields(discriminator, trace, in, schema) @@ -1014,63 +1014,63 @@ object JsonCodec { } } - private[codec] def caseClass6Decoder[A1, A2, A3, A4, A5, A6, Z](discriminator: Int, schema: Schema.CaseClass6[A1, A2, A3, A4, A5, A6, Z]): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => + private[codec] def caseClass6Decoder[A1, A2, A3, A4, A5, A6, Z](discriminator: Int, schema: Schema.CaseClass6[A1, A2, A3, A4, A5, A6, Z])(implicit config: JsonCodec.Config): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => { val buffer: Array[Any] = unsafeDecodeFields(discriminator, trace, in, schema) schema.construct(buffer(0).asInstanceOf[A1], buffer(1).asInstanceOf[A2], buffer(2).asInstanceOf[A3], buffer(3).asInstanceOf[A4], buffer(4).asInstanceOf[A5], buffer(5).asInstanceOf[A6]) } } - private[codec] def caseClass7Decoder[A1, A2, A3, A4, A5, A6, A7, Z](discriminator: Int, schema: Schema.CaseClass7[A1, A2, A3, A4, A5, A6, A7, Z]): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => + private[codec] def caseClass7Decoder[A1, A2, A3, A4, A5, A6, A7, Z](discriminator: Int, schema: Schema.CaseClass7[A1, A2, A3, A4, A5, A6, A7, Z])(implicit config: JsonCodec.Config): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => { val buffer: Array[Any] = unsafeDecodeFields(discriminator, trace, in, schema) schema.construct(buffer(0).asInstanceOf[A1], buffer(1).asInstanceOf[A2], buffer(2).asInstanceOf[A3], buffer(3).asInstanceOf[A4], buffer(4).asInstanceOf[A5], buffer(5).asInstanceOf[A6], buffer(6).asInstanceOf[A7]) } } - private[codec] def caseClass8Decoder[A1, A2, A3, A4, A5, A6, A7, A8, Z](discriminator: Int, schema: Schema.CaseClass8[A1, A2, A3, A4, A5, A6, A7, A8, Z]): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => + private[codec] def caseClass8Decoder[A1, A2, A3, A4, A5, A6, A7, A8, Z](discriminator: Int, schema: Schema.CaseClass8[A1, A2, A3, A4, A5, A6, A7, A8, Z])(implicit config: JsonCodec.Config): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => { val buffer: Array[Any] = unsafeDecodeFields(discriminator, trace, in, schema) schema.construct(buffer(0).asInstanceOf[A1], buffer(1).asInstanceOf[A2], buffer(2).asInstanceOf[A3], buffer(3).asInstanceOf[A4], buffer(4).asInstanceOf[A5], buffer(5).asInstanceOf[A6], buffer(6).asInstanceOf[A7], buffer(7).asInstanceOf[A8]) } } - private[codec] def caseClass9Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, Z](discriminator: Int, schema: Schema.CaseClass9[A1, A2, A3, A4, A5, A6, A7, A8, A9, Z]): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => + private[codec] def caseClass9Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, Z](discriminator: Int, schema: Schema.CaseClass9[A1, A2, A3, A4, A5, A6, A7, A8, A9, Z])(implicit config: JsonCodec.Config): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => { val buffer: Array[Any] = unsafeDecodeFields(discriminator, trace, in, schema) schema.construct(buffer(0).asInstanceOf[A1], buffer(1).asInstanceOf[A2], buffer(2).asInstanceOf[A3], buffer(3).asInstanceOf[A4], buffer(4).asInstanceOf[A5], buffer(5).asInstanceOf[A6], buffer(6).asInstanceOf[A7], buffer(7).asInstanceOf[A8], buffer(8).asInstanceOf[A9]) } } - private[codec] def caseClass10Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, Z](discriminator: Int, schema: Schema.CaseClass10[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, Z]): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => + private[codec] def caseClass10Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, Z](discriminator: Int, schema: Schema.CaseClass10[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, Z])(implicit config: JsonCodec.Config): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => { val buffer: Array[Any] = unsafeDecodeFields(discriminator, trace, in, schema) schema.construct(buffer(0).asInstanceOf[A1], buffer(1).asInstanceOf[A2], buffer(2).asInstanceOf[A3], buffer(3).asInstanceOf[A4], buffer(4).asInstanceOf[A5], buffer(5).asInstanceOf[A6], buffer(6).asInstanceOf[A7], buffer(7).asInstanceOf[A8], buffer(8).asInstanceOf[A9], buffer(9).asInstanceOf[A10]) } } - private[codec] def caseClass11Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, Z](discriminator: Int, schema: Schema.CaseClass11[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, Z]): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => + private[codec] def caseClass11Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, Z](discriminator: Int, schema: Schema.CaseClass11[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, Z])(implicit config: JsonCodec.Config): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => { val buffer: Array[Any] = unsafeDecodeFields(discriminator, trace, in, schema) schema.construct(buffer(0).asInstanceOf[A1], buffer(1).asInstanceOf[A2], buffer(2).asInstanceOf[A3], buffer(3).asInstanceOf[A4], buffer(4).asInstanceOf[A5], buffer(5).asInstanceOf[A6], buffer(6).asInstanceOf[A7], buffer(7).asInstanceOf[A8], buffer(8).asInstanceOf[A9], buffer(9).asInstanceOf[A10], buffer(10).asInstanceOf[A11]) } } - private[codec] def caseClass12Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, Z](discriminator: Int, schema: Schema.CaseClass12[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, Z]): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => + private[codec] def caseClass12Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, Z](discriminator: Int, schema: Schema.CaseClass12[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, Z])(implicit config: JsonCodec.Config): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => { val buffer: Array[Any] = unsafeDecodeFields(discriminator, trace, in, schema) schema.construct(buffer(0).asInstanceOf[A1], buffer(1).asInstanceOf[A2], buffer(2).asInstanceOf[A3], buffer(3).asInstanceOf[A4], buffer(4).asInstanceOf[A5], buffer(5).asInstanceOf[A6], buffer(6).asInstanceOf[A7], buffer(7).asInstanceOf[A8], buffer(8).asInstanceOf[A9], buffer(9).asInstanceOf[A10], buffer(10).asInstanceOf[A11], buffer(11).asInstanceOf[A12]) } } - private[codec] def caseClass13Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, Z](discriminator: Int, schema: Schema.CaseClass13[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, Z]): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => + private[codec] def caseClass13Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, Z](discriminator: Int, schema: Schema.CaseClass13[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, Z])(implicit config: JsonCodec.Config): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => { val buffer: Array[Any] = unsafeDecodeFields(discriminator, trace, in, schema) schema.construct(buffer(0).asInstanceOf[A1], buffer(1).asInstanceOf[A2], buffer(2).asInstanceOf[A3], buffer(3).asInstanceOf[A4], buffer(4).asInstanceOf[A5], buffer(5).asInstanceOf[A6], buffer(6).asInstanceOf[A7], buffer(7).asInstanceOf[A8], buffer(8).asInstanceOf[A9], buffer(9).asInstanceOf[A10], buffer(10).asInstanceOf[A11], buffer(11).asInstanceOf[A12], buffer(12).asInstanceOf[A13]) } } - private[codec] def caseClass14Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, Z](discriminator: Int, schema: Schema.CaseClass14[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, Z]): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => + private[codec] def caseClass14Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, Z](discriminator: Int, schema: Schema.CaseClass14[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, Z])(implicit config: JsonCodec.Config): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => { val buffer: Array[Any] = unsafeDecodeFields(discriminator, trace, in, schema) schema.construct( @@ -1092,7 +1092,7 @@ object JsonCodec { } } - private[codec] def caseClass15Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, Z](discriminator: Int, schema: Schema.CaseClass15[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, Z]): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => + private[codec] def caseClass15Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, Z](discriminator: Int, schema: Schema.CaseClass15[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, Z])(implicit config: JsonCodec.Config): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => { val buffer: Array[Any] = unsafeDecodeFields(discriminator, trace, in, schema) schema.construct( @@ -1115,7 +1115,7 @@ object JsonCodec { } } - private[codec] def caseClass16Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, Z](discriminator: Int, schema: Schema.CaseClass16[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, Z]): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => + private[codec] def caseClass16Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, Z](discriminator: Int, schema: Schema.CaseClass16[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, Z])(implicit config: JsonCodec.Config): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => { val buffer: Array[Any] = unsafeDecodeFields(discriminator, trace, in, schema) schema.construct( @@ -1139,7 +1139,7 @@ object JsonCodec { } } - private[codec] def caseClass17Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, Z](discriminator: Int, schema: Schema.CaseClass17[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, Z]): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => + private[codec] def caseClass17Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, Z](discriminator: Int, schema: Schema.CaseClass17[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, Z])(implicit config: JsonCodec.Config): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => { val buffer: Array[Any] = unsafeDecodeFields(discriminator, trace, in, schema) schema.construct( @@ -1164,7 +1164,7 @@ object JsonCodec { } } - private[codec] def caseClass18Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, Z](discriminator: Int, schema: Schema.CaseClass18[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, Z]): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => + private[codec] def caseClass18Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, Z](discriminator: Int, schema: Schema.CaseClass18[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, Z])(implicit config: JsonCodec.Config): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => { val buffer: Array[Any] = unsafeDecodeFields(discriminator, trace, in, schema) schema.construct( @@ -1190,7 +1190,7 @@ object JsonCodec { } } - private[codec] def caseClass19Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, Z](discriminator: Int, schema: Schema.CaseClass19[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, Z]): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => + private[codec] def caseClass19Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, Z](discriminator: Int, schema: Schema.CaseClass19[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, Z])(implicit config: JsonCodec.Config): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => { val buffer: Array[Any] = unsafeDecodeFields(discriminator, trace, in, schema) schema.construct( @@ -1217,7 +1217,7 @@ object JsonCodec { } } - private[codec] def caseClass20Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, Z](discriminator: Int, schema: Schema.CaseClass20[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, Z]): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => + private[codec] def caseClass20Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, Z](discriminator: Int, schema: Schema.CaseClass20[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, Z])(implicit config: JsonCodec.Config): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => { val buffer: Array[Any] = unsafeDecodeFields(discriminator, trace, in, schema) schema.construct( @@ -1245,7 +1245,7 @@ object JsonCodec { } } - private[codec] def caseClass21Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, Z](discriminator: Int, schema: Schema.CaseClass21[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, Z]): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => + private[codec] def caseClass21Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, Z](discriminator: Int, schema: Schema.CaseClass21[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, Z])(implicit config: JsonCodec.Config): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => { val buffer: Array[Any] = unsafeDecodeFields(discriminator, trace, in, schema) @@ -1275,7 +1275,7 @@ object JsonCodec { } } - private[codec] def caseClass22Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, Z](discriminator: Int, schema: Schema.CaseClass22[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, Z]): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => +private[codec] def caseClass22Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, Z](discriminator: Int, schema: Schema.CaseClass22[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, Z])(implicit config: JsonCodec.Config): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => { val buffer: Array[Any] = unsafeDecodeFields(discriminator, trace, in, schema) @@ -1306,66 +1306,149 @@ object JsonCodec { } } - private def unsafeDecodeFields[Z](discriminator: Int, trace: List[JsonError], in: RetractReader, caseClassSchema: Schema.Record[Z]) = { - val fields = caseClassSchema.fields - val len: Int = fields.length - val buffer = Array.ofDim[Any](len) - val fieldNames = fields.map(_.name.asInstanceOf[String]).toArray - val spans: Array[JsonError] = fields.map(_.name.asInstanceOf[String]).toArray.map(JsonError.ObjectAccess(_)) - val schemas: Array[Schema[_]] = fields.map(_.schema).toArray - val fieldAliases = fields.flatMap { - case Schema.Field(name, _, annotations, _, _, _) => - val aliases = annotations.collectFirst { case a: fieldNameAliases => a.aliases }.getOrElse(Nil) - aliases.map(_ -> fieldNames.indexOf(name)) :+ (name -> fieldNames.indexOf(name)) - }.toMap - val aliasesMatrix = fieldAliases.keys.toArray ++ fieldNames - val rejectExtraFields = caseClassSchema.annotations.collectFirst({ case _: rejectExtraFields => () }).isDefined - - @tailrec - def loop(index: Int, in: RetractReader): Unit = { - val fieldRaw = Lexer.field(trace, in, new StringMatrix(aliasesMatrix)) - if (index == discriminator) { - Lexer.skipValue(trace, in) - } else { - fieldRaw match { - case -1 if index == discriminator => Lexer.skipValue(trace, in) - case -1 if rejectExtraFields => throw UnsafeJson(JsonError.Message("extra field") :: trace) - case -1 => Lexer.skipValue(trace, in) - case idx => - val field = fieldAliases.getOrElse(aliasesMatrix(idx), -1) - if (buffer(field) != null) - throw UnsafeJson(JsonError.Message("duplicate") :: trace) - else - buffer(field) = schemaDecoder(schemas(field)).unsafeDecode(spans(field) :: trace, in) - } - } - if (Lexer.nextField(trace, in)) loop(index + 1, in) + // private def unsafeDecodeFields[Z](discriminator: Int, trace: List[JsonError], in: RetractReader, caseClassSchema: Schema.Record[Z]) = { + // val fields = caseClassSchema.fields + // val len: Int = fields.length + // val buffer = Array.ofDim[Any](len) + // val fieldNames = fields.map(_.name.asInstanceOf[String]).toArray + // val spans: Array[JsonError] = fields.map(_.name.asInstanceOf[String]).toArray.map(JsonError.ObjectAccess(_)) + // val schemas: Array[Schema[_]] = fields.map(_.schema).toArray + // val fieldAliases = fields.flatMap { + // case Schema.Field(name, _, annotations, _, _, _) => + // val aliases = annotations.collectFirst { case a: fieldNameAliases => a.aliases }.getOrElse(Nil) + // aliases.map(_ -> fieldNames.indexOf(name)) :+ (name -> fieldNames.indexOf(name)) + // }.toMap + // val aliasesMatrix = fieldAliases.keys.toArray ++ fieldNames + // val rejectExtraFields = caseClassSchema.annotations.collectFirst({ case _: rejectExtraFields => () }).isDefined + + // @tailrec + // def loop(index: Int, in: RetractReader): Unit = { + // val fieldRaw = Lexer.field(trace, in, new StringMatrix(aliasesMatrix)) + // if (index == discriminator) { + // Lexer.skipValue(trace, in) + // } else { + // fieldRaw match { + // case -1 if index == discriminator => Lexer.skipValue(trace, in) + // case -1 if rejectExtraFields => throw UnsafeJson(JsonError.Message("extra field") :: trace) + // case -1 => Lexer.skipValue(trace, in) + // case idx => + // val field = fieldAliases.getOrElse(aliasesMatrix(idx), -1) + // if (buffer(field) != null) + // throw UnsafeJson(JsonError.Message("duplicate") :: trace) + // else + // buffer(field) = schemaDecoder(schemas(field)).unsafeDecode(spans(field) :: trace, in) + // } + // } + // if (Lexer.nextField(trace, in)) loop(index + 1, in) + // } + + // if (discriminator == -1) { + // Lexer.char(trace, in, '{') + // if (Lexer.firstField(trace, in)) loop(0, in) + // } else if (discriminator == -2) { + // if (Lexer.nextField(trace, in)) loop(0, in) + // } else { + // val rr = RecordingReader(in) + // if (Lexer.firstField(trace, rr)) loop(0, rr) + // } + + // var i = 0 + // while (i < len) { + // if (buffer(i) == null) { + + // if ((fields(i).optional || fields(i).transient) && fields(i).defaultValue.isDefined) + // buffer(i) = fields(i).defaultValue.get + // else + // buffer(i) = schemaDecoder(schemas(i)).unsafeDecodeMissing(spans(i) :: trace) + + // } + // i += 1 + // } + // buffer + // } + private def unsafeDecodeFields[Z](discriminator: Int, trace: List[JsonError], in: RetractReader, caseClassSchema: Schema.Record[Z])(implicit config: JsonCodec.Config) = { + val fields = caseClassSchema.fields + val len: Int = fields.length + val buffer = Array.ofDim[Any](len) + val fieldNames = fields.map(_.name.asInstanceOf[String]).toArray + val spans: Array[JsonError] = fields.map(_.name.asInstanceOf[String]).toArray.map(JsonError.ObjectAccess(_)) + val schemas: Array[Schema[_]] = fields.map(_.schema).toArray + val fieldAliases = fields.flatMap { + case Schema.Field(name, _, annotations, _, _, _) => + val aliases = annotations.collectFirst { case a: fieldNameAliases => a.aliases }.getOrElse(Nil) + aliases.map(_ -> fieldNames.indexOf(name)) :+ (name -> fieldNames.indexOf(name)) + }.toMap + val aliasesMatrix = fieldAliases.keys.toArray ++ fieldNames + val rejectExtraFields = caseClassSchema.annotations.collectFirst({ case _: rejectExtraFields => () }).isDefined + + @tailrec + def loop(index: Int, in: RetractReader): Unit = { + val fieldRaw = Lexer.field(trace, in, new StringMatrix(aliasesMatrix)) + if (index == discriminator) { + Lexer.skipValue(trace, in) + } else { + fieldRaw match { + case -1 if index == discriminator => Lexer.skipValue(trace, in) + case -1 if rejectExtraFields => throw UnsafeJson(JsonError.Message("extra field") :: trace) + case -1 => Lexer.skipValue(trace, in) + case idx => + val field = fieldAliases.getOrElse(aliasesMatrix(idx), -1) + if (buffer(field) != null) + throw UnsafeJson(JsonError.Message("duplicate") :: trace) + else + buffer(field) = schemaDecoder(schemas(field)).unsafeDecode(spans(field) :: trace, in) } + } + if (Lexer.nextField(trace, in)) loop(index + 1, in) + } - if (discriminator == -1) { - Lexer.char(trace, in, '{') - if (Lexer.firstField(trace, in)) loop(0, in) - } else if (discriminator == -2) { - if (Lexer.nextField(trace, in)) loop(0, in) + if (discriminator == -1) { + Lexer.char(trace, in, '{') + if (Lexer.firstField(trace, in)) loop(0, in) + } else if (discriminator == -2) { + if (Lexer.nextField(trace, in)) loop(0, in) + } else { + val rr = RecordingReader(in) + if (Lexer.firstField(trace, rr)) loop(0, rr) + } + + var i = 0 + while (i < len) { + if (buffer(i) == null) { + if ((fields(i).optional || fields(i).transient) && fields(i).defaultValue.isDefined) { + buffer(i) = fields(i).defaultValue.get + } else if (config.ignoreEmptyCollections && isCollectionSchema(schemas(i))) { + buffer(i) = createEmptyCollection(schemas(i)) } else { - val rr = RecordingReader(in) - if (Lexer.firstField(trace, rr)) loop(0, rr) + buffer(i) = schemaDecoder(schemas(i)).unsafeDecodeMissing(spans(i) :: trace) } + } + i += 1 + } + buffer +} - var i = 0 - while (i < len) { - if (buffer(i) == null) { +// Helper method to check if a schema represents a collection type +private def isCollectionSchema(schema: Schema[_]): Boolean = { + schema match { + case Schema.Sequence(_, _, _, _, _) => true + case Schema.Set(_, _) => true + case Schema.Map(_, _, _) => true + case _ => false + } +} - if ((fields(i).optional || fields(i).transient) && fields(i).defaultValue.isDefined) - buffer(i) = fields(i).defaultValue.get - else - buffer(i) = schemaDecoder(schemas(i)).unsafeDecodeMissing(spans(i) :: trace) - } - i += 1 - } - buffer - } +// Helper method to create an empty collection based on the schema +private def createEmptyCollection(schema: Schema[_]): Any = { + schema match { + case Schema.Sequence(_, _, _,_,_) => List.empty + case Schema.Set(_, _) => Set.empty + case Schema.Map(_, _,_) => Map.empty + case _ => throw new IllegalArgumentException("Unsupported collection schema") + } +} + } } diff --git a/zio-schema-json/shared/src/test/scala-2/zio/schema/codec/JsonCodecSpec.scala b/zio-schema-json/shared/src/test/scala-2/zio/schema/codec/JsonCodecSpec.scala index 0393c8a7a..3ce93e8a5 100644 --- a/zio-schema-json/shared/src/test/scala-2/zio/schema/codec/JsonCodecSpec.scala +++ b/zio-schema-json/shared/src/test/scala-2/zio/schema/codec/JsonCodecSpec.scala @@ -1372,8 +1372,8 @@ object JsonCodecSpec extends ZIOSpecDefault { val dyn = DynamicValue.fromSchemaAndValue(schema, value) ZStream .succeed(dyn) - .via(JsonCodec.schemaBasedBinaryCodec(Schema.dynamicValue).streamEncoder) - .via(JsonCodec.schemaBasedBinaryCodec(Schema.dynamicValue).streamDecoder) + .via(JsonCodec.schemaBasedBinaryCodec(Schema.dynamicValue, JsonCodec.Config.default).streamEncoder) + .via(JsonCodec.schemaBasedBinaryCodec(Schema.dynamicValue, JsonCodec.Config.default).streamDecoder) .map(_.toTypedValue(schema)) .runHead .map { result => @@ -1416,7 +1416,7 @@ object JsonCodecSpec extends ZIOSpecDefault { ) = { val stream = ZStream .succeed(value) - .via(JsonCodec.schemaBasedBinaryCodec(cfg)(schema).streamEncoder) + .via(JsonCodec.schemaBasedBinaryCodec(cfg)(schema, JsonCodec.Config.default).streamEncoder) .runCollect .tap { chunk => printLine(s"${new String(chunk.toArray)}").when(print).ignore @@ -1432,7 +1432,7 @@ object JsonCodecSpec extends ZIOSpecDefault { ) = { val stream = ZStream .succeed(value) - .via(JsonCodec.schemaBasedBinaryCodec[A](cfg)(schema).streamEncoder) + .via(JsonCodec.schemaBasedBinaryCodec[A](cfg)(schema, JsonCodec.Config.default).streamEncoder) .runCollect .map(chunk => new String(chunk.toArray)) assertZIO(stream)(equalTo(json)) @@ -1441,7 +1441,7 @@ object JsonCodecSpec extends ZIOSpecDefault { def assertEncodesJson[A](schema: Schema[A], value: A)(implicit enc: JsonEncoder[A]): ZIO[Any, Nothing, TestResult] = { val stream = ZStream .succeed(value) - .via(JsonCodec.schemaBasedBinaryCodec[A](schema).streamEncoder) + .via(JsonCodec.schemaBasedBinaryCodec[A](schema, JsonCodec.Config.default).streamEncoder) .runCollect assertZIO(stream)(equalTo(jsonEncoded(value))) } @@ -1454,7 +1454,7 @@ object JsonCodecSpec extends ZIOSpecDefault { ) = { val stream = ZStream .fromChunk(charSequenceToByteChunk(json)) - .via(JsonCodec.schemaBasedBinaryCodec[A](cfg)(schema).streamDecoder) + .via(JsonCodec.schemaBasedBinaryCodec[A](cfg)(schema, JsonCodec.Config.default).streamDecoder) .catchAll(ZStream.succeed[DecodeError](_)) .runHead assertZIO(stream)(isSome(equalTo(ReadError(Cause.empty, JsonError.render(errors))))) @@ -1466,7 +1466,7 @@ object JsonCodecSpec extends ZIOSpecDefault { chunk: Chunk[Byte], cfg: JsonCodec.Config = JsonCodec.Config.default ) = { - val result = ZStream.fromChunk(chunk).via(JsonCodec.schemaBasedBinaryCodec[A](cfg)(schema).streamDecoder).runCollect + val result = ZStream.fromChunk(chunk).via(JsonCodec.schemaBasedBinaryCodec[A](cfg)(schema, JsonCodec.Config.default).streamDecoder).runCollect assertZIO(result)(equalTo(Chunk(value))) } @@ -1476,13 +1476,13 @@ object JsonCodecSpec extends ZIOSpecDefault { ): ZIO[Any, Nothing, TestResult] = ZStream .succeed(value) - .via(JsonCodec.schemaBasedBinaryCodec[zio.schema.Fallback[A, B]](JsonCodec.Config.default)(schema).streamEncoder) + .via(JsonCodec.schemaBasedBinaryCodec[zio.schema.Fallback[A, B]](JsonCodec.Config.default)(schema, JsonCodec.Config.default).streamEncoder) .runCollect .flatMap { encoded => ZStream .fromChunk(encoded) .via( - JsonCodec.schemaBasedBinaryCodec[zio.schema.Fallback[A, B]](JsonCodec.Config.default)(schema).streamDecoder + JsonCodec.schemaBasedBinaryCodec[zio.schema.Fallback[A, B]](JsonCodec.Config.default)(schema, JsonCodec.Config.default).streamDecoder ) .runCollect } @@ -1514,13 +1514,13 @@ object JsonCodecSpec extends ZIOSpecDefault { ZStream .succeed(value) .tap(value => printLine(s"Input Value: $value").when(print).ignore) - .via(JsonCodec.schemaBasedBinaryCodec[A1](cfg)(encodingSchema).streamEncoder) + .via(JsonCodec.schemaBasedBinaryCodec[A1](cfg)(encodingSchema, JsonCodec.Config.default).streamEncoder) .runCollect .tap(encoded => printLine(s"Encoded: ${new String(encoded.toArray)}").when(print).ignore) .flatMap { encoded => ZStream .fromChunk(encoded) - .via(JsonCodec.schemaBasedBinaryCodec[A2](cfg)(decodingSchema).streamDecoder) + .via(JsonCodec.schemaBasedBinaryCodec[A2](cfg)(decodingSchema, JsonCodec.Config.default).streamDecoder) .runCollect .tapError { err => printLineError(s"Decoding failed for input ${new String(encoded.toArray)}\nError Message: $err") From 0f70c17e95d1f30b7aac795c92064648d0b4b06c Mon Sep 17 00:00:00 2001 From: David Anyatonwu Date: Sun, 9 Jun 2024 01:32:02 +0100 Subject: [PATCH 2/4] fix format issues and remove unnecessary comments --- .../schema/example/example1/Example1.scala | 16 +- .../schema/example/example2/Example2.scala | 6 +- .../schema/example/example3/Example3.scala | 3 +- .../scala/zio/schema/codec/JsonCodec.scala | 260 +++++++----------- .../zio/schema/codec/JsonCodecSpec.scala | 18 +- 5 files changed, 127 insertions(+), 176 deletions(-) diff --git a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example1/Example1.scala b/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example1/Example1.scala index 22c33e5c6..6bdc16873 100644 --- a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example1/Example1.scala +++ b/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example1/Example1.scala @@ -130,7 +130,6 @@ object MacroConstruction { implicit val schemaPerson: Schema[Person] = DeriveSchema.gen[Person] - val schemaPaymentMethod: Schema[PaymentMethod] = DeriveSchema.gen[PaymentMethod] val schemaCustomer: Schema[Customer] = DeriveSchema.gen[Customer] @@ -144,8 +143,7 @@ object JsonSample extends zio.ZIOAppDefault { import ManualConstruction._ import zio.schema.codec.JsonCodec import zio.stream.ZStream - implicit val defaultConfig: JsonCodec.Config = JsonCodec.Config.default - + implicit val defaultConfig: JsonCodec.Config = JsonCodec.Config.default override def run: ZIO[Environment with ZIOAppArgs, Any, Any] = for { @@ -191,9 +189,7 @@ object CombiningExample extends ZIOAppDefault { import ManualConstruction._ import zio.schema.codec.{ JsonCodec, ProtobufCodec } import zio.stream.ZStream - implicit val defaultConfig: JsonCodec.Config = JsonCodec.Config.default - - + implicit val defaultConfig: JsonCodec.Config = JsonCodec.Config.default override def run: ZIO[Environment with ZIOAppArgs, Any, Any] = for { @@ -229,7 +225,7 @@ object DictionaryExample extends ZIOAppDefault { import MacroConstruction._ import zio.schema.codec.JsonCodec import zio.stream.ZStream - implicit val defaultConfig: JsonCodec.Config = JsonCodec.Config.default + implicit val defaultConfig: JsonCodec.Config = JsonCodec.Config.default override def run: ZIO[Environment with ZIOAppArgs, Any, Any] = for { @@ -238,12 +234,14 @@ object DictionaryExample extends ZIOAppDefault { dictionary = Map("m" -> person) dictionaryToJson = JsonCodec .schemaBasedBinaryCodec[scala.collection.immutable.Map[String, Person]]( - schemaPersonDictionaryFromMacro, defaultConfig + schemaPersonDictionaryFromMacro, + defaultConfig ) .streamEncoder jsonToDictionary = JsonCodec .schemaBasedBinaryCodec[scala.collection.immutable.Map[String, Person]]( - schemaPersonDictionaryFromMacro, defaultConfig + schemaPersonDictionaryFromMacro, + defaultConfig ) .streamDecoder newPersonDictionary <- ZStream(dictionary) diff --git a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example2/Example2.scala b/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example2/Example2.scala index b2f93d872..64bfdc95c 100644 --- a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example2/Example2.scala +++ b/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example2/Example2.scala @@ -153,8 +153,7 @@ import dev.zio.schema.example.example2.Domain._ object JsonSample extends zio.ZIOAppDefault { import zio.schema.codec.JsonCodec import zio.stream.ZStream - implicit val defaultConfig: JsonCodec.Config = JsonCodec.Config.default - + implicit val defaultConfig: JsonCodec.Config = JsonCodec.Config.default override def run: ZIO[Environment with ZIOAppArgs, Any, Any] = for { @@ -198,8 +197,7 @@ object ProtobufExample extends ZIOAppDefault { object CombiningExample extends zio.ZIOAppDefault { import zio.schema.codec.{ JsonCodec, ProtobufCodec } import zio.stream.ZStream - implicit val defaultConfig: JsonCodec.Config = JsonCodec.Config.default - + implicit val defaultConfig: JsonCodec.Config = JsonCodec.Config.default override def run: ZIO[Environment with ZIOAppArgs, Any, Any] = for { diff --git a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example3/Example3.scala b/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example3/Example3.scala index 1def541a3..c9dd980ec 100644 --- a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example3/Example3.scala +++ b/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example3/Example3.scala @@ -57,8 +57,7 @@ private[example3] object Domain { object Example3 extends ZIOAppDefault { import dev.zio.schema.example.example3.Domain._ import zio.schema.codec.JsonCodec - implicit val defaultConfig: JsonCodec.Config = JsonCodec.Config.default - + implicit val defaultConfig: JsonCodec.Config = JsonCodec.Config.default val personTransformation: Schema[Person] = PersonDTO.schema.transform[Person]( (dto: PersonDTO) => Person(dto.firstname + " " + dto.lastname, dto.years), diff --git a/zio-schema-json/shared/src/main/scala/zio/schema/codec/JsonCodec.scala b/zio-schema-json/shared/src/main/scala/zio/schema/codec/JsonCodec.scala index 61208ff0d..87bc32938 100644 --- a/zio-schema-json/shared/src/main/scala/zio/schema/codec/JsonCodec.scala +++ b/zio-schema-json/shared/src/main/scala/zio/schema/codec/JsonCodec.scala @@ -656,7 +656,9 @@ object JsonCodec { case _ => None } - private def dynamicDecoder(schema: Schema.Dynamic)(implicit config: JsonCodec.Config): ZJsonDecoder[DynamicValue] = { + private def dynamicDecoder( + schema: Schema.Dynamic + )(implicit config: JsonCodec.Config): ZJsonDecoder[DynamicValue] = { val directMapping = schema.annotations.exists { case directDynamicMapping() => true case _ => false @@ -683,7 +685,9 @@ object JsonCodec { case Json.Null => DynamicValue.NoneValue } - private def enumDecoder[Z](parentSchema: Schema.Enum[Z], cases: Schema.Case[Z, _]*)(implicit config: JsonCodec.Config): ZJsonDecoder[Z] = { + private def enumDecoder[Z](parentSchema: Schema.Enum[Z], cases: Schema.Case[Z, _]*)( + implicit config: JsonCodec.Config + ): ZJsonDecoder[Z] = { val caseNameAliases = cases.flatMap { case Schema.Case(name, _, _, _, _, annotations) => annotations.flatMap { @@ -801,35 +805,38 @@ object JsonCodec { private def deAliasCaseName(alias: String, caseNameAliases: Map[String, String]): String = caseNameAliases.getOrElse(alias, alias) - private def recordDecoder[Z](structure: Seq[Schema.Field[Z, _]])(implicit config: JsonCodec.Config): ZJsonDecoder[ListMap[String, Any]] = { - (trace: List[JsonError], in: RetractReader) => - { - val builder: ChunkBuilder[(String, Any)] = zio.ChunkBuilder.make[(String, Any)](structure.size) - Lexer.char(trace, in, '{') - if (Lexer.firstField(trace, in)) { - while ({ - val field = Lexer.string(trace, in).toString - structure.find(_.name == field) match { - case Some(Schema.Field(label, schema, _, _, _, _)) => - val trace_ = JsonError.ObjectAccess(label) :: trace - Lexer.char(trace_, in, ':') - val value = schemaDecoder(schema).unsafeDecode(trace_, in) - builder += ((JsonFieldDecoder.string.unsafeDecodeField(trace_, label), value)) - case None => - Lexer.char(trace, in, ':') - Lexer.skipValue(trace, in) + private def recordDecoder[Z](structure: Seq[Schema.Field[Z, _]])( + implicit config: JsonCodec.Config + ): ZJsonDecoder[ListMap[String, Any]] = { (trace: List[JsonError], in: RetractReader) => + { + val builder: ChunkBuilder[(String, Any)] = zio.ChunkBuilder.make[(String, Any)](structure.size) + Lexer.char(trace, in, '{') + if (Lexer.firstField(trace, in)) { + while ({ + val field = Lexer.string(trace, in).toString + structure.find(_.name == field) match { + case Some(Schema.Field(label, schema, _, _, _, _)) => + val trace_ = JsonError.ObjectAccess(label) :: trace + Lexer.char(trace_, in, ':') + val value = schemaDecoder(schema).unsafeDecode(trace_, in) + builder += ((JsonFieldDecoder.string.unsafeDecodeField(trace_, label), value)) + case None => + Lexer.char(trace, in, ':') + Lexer.skipValue(trace, in) - } - (Lexer.nextField(trace, in)) - }) { - () } + (Lexer.nextField(trace, in)) + }) { + () } - (ListMap.newBuilder[String, Any] ++= builder.result()).result() } + (ListMap.newBuilder[String, Any] ++= builder.result()).result() + } } - private def fallbackDecoder[A, B](schema: Schema.Fallback[A, B])(implicit config: JsonCodec.Config): ZJsonDecoder[Fallback[A, B]] = + private def fallbackDecoder[A, B]( + schema: Schema.Fallback[A, B] + )(implicit config: JsonCodec.Config): ZJsonDecoder[Fallback[A, B]] = new ZJsonDecoder[Fallback[A, B]] { def unsafeDecode(trace: List[JsonError], in: RetractReader): Fallback[A, B] = { @@ -1275,7 +1282,7 @@ object JsonCodec { } } -private[codec] def caseClass22Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, Z](discriminator: Int, schema: Schema.CaseClass22[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, Z])(implicit config: JsonCodec.Config): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => + private[codec] def caseClass22Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, Z](discriminator: Int, schema: Schema.CaseClass22[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, Z])(implicit config: JsonCodec.Config): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => { val buffer: Array[Any] = unsafeDecodeFields(discriminator, trace, in, schema) @@ -1306,148 +1313,85 @@ private[codec] def caseClass22Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A } } - // private def unsafeDecodeFields[Z](discriminator: Int, trace: List[JsonError], in: RetractReader, caseClassSchema: Schema.Record[Z]) = { - // val fields = caseClassSchema.fields - // val len: Int = fields.length - // val buffer = Array.ofDim[Any](len) - // val fieldNames = fields.map(_.name.asInstanceOf[String]).toArray - // val spans: Array[JsonError] = fields.map(_.name.asInstanceOf[String]).toArray.map(JsonError.ObjectAccess(_)) - // val schemas: Array[Schema[_]] = fields.map(_.schema).toArray - // val fieldAliases = fields.flatMap { - // case Schema.Field(name, _, annotations, _, _, _) => - // val aliases = annotations.collectFirst { case a: fieldNameAliases => a.aliases }.getOrElse(Nil) - // aliases.map(_ -> fieldNames.indexOf(name)) :+ (name -> fieldNames.indexOf(name)) - // }.toMap - // val aliasesMatrix = fieldAliases.keys.toArray ++ fieldNames - // val rejectExtraFields = caseClassSchema.annotations.collectFirst({ case _: rejectExtraFields => () }).isDefined - - // @tailrec - // def loop(index: Int, in: RetractReader): Unit = { - // val fieldRaw = Lexer.field(trace, in, new StringMatrix(aliasesMatrix)) - // if (index == discriminator) { - // Lexer.skipValue(trace, in) - // } else { - // fieldRaw match { - // case -1 if index == discriminator => Lexer.skipValue(trace, in) - // case -1 if rejectExtraFields => throw UnsafeJson(JsonError.Message("extra field") :: trace) - // case -1 => Lexer.skipValue(trace, in) - // case idx => - // val field = fieldAliases.getOrElse(aliasesMatrix(idx), -1) - // if (buffer(field) != null) - // throw UnsafeJson(JsonError.Message("duplicate") :: trace) - // else - // buffer(field) = schemaDecoder(schemas(field)).unsafeDecode(spans(field) :: trace, in) - // } - // } - // if (Lexer.nextField(trace, in)) loop(index + 1, in) - // } - - // if (discriminator == -1) { - // Lexer.char(trace, in, '{') - // if (Lexer.firstField(trace, in)) loop(0, in) - // } else if (discriminator == -2) { - // if (Lexer.nextField(trace, in)) loop(0, in) - // } else { - // val rr = RecordingReader(in) - // if (Lexer.firstField(trace, rr)) loop(0, rr) - // } - - // var i = 0 - // while (i < len) { - // if (buffer(i) == null) { - - // if ((fields(i).optional || fields(i).transient) && fields(i).defaultValue.isDefined) - // buffer(i) = fields(i).defaultValue.get - // else - // buffer(i) = schemaDecoder(schemas(i)).unsafeDecodeMissing(spans(i) :: trace) - - // } - // i += 1 - // } - // buffer - // } private def unsafeDecodeFields[Z](discriminator: Int, trace: List[JsonError], in: RetractReader, caseClassSchema: Schema.Record[Z])(implicit config: JsonCodec.Config) = { - val fields = caseClassSchema.fields - val len: Int = fields.length - val buffer = Array.ofDim[Any](len) - val fieldNames = fields.map(_.name.asInstanceOf[String]).toArray - val spans: Array[JsonError] = fields.map(_.name.asInstanceOf[String]).toArray.map(JsonError.ObjectAccess(_)) - val schemas: Array[Schema[_]] = fields.map(_.schema).toArray - val fieldAliases = fields.flatMap { - case Schema.Field(name, _, annotations, _, _, _) => - val aliases = annotations.collectFirst { case a: fieldNameAliases => a.aliases }.getOrElse(Nil) - aliases.map(_ -> fieldNames.indexOf(name)) :+ (name -> fieldNames.indexOf(name)) - }.toMap - val aliasesMatrix = fieldAliases.keys.toArray ++ fieldNames - val rejectExtraFields = caseClassSchema.annotations.collectFirst({ case _: rejectExtraFields => () }).isDefined - - @tailrec - def loop(index: Int, in: RetractReader): Unit = { - val fieldRaw = Lexer.field(trace, in, new StringMatrix(aliasesMatrix)) - if (index == discriminator) { - Lexer.skipValue(trace, in) - } else { - fieldRaw match { - case -1 if index == discriminator => Lexer.skipValue(trace, in) - case -1 if rejectExtraFields => throw UnsafeJson(JsonError.Message("extra field") :: trace) - case -1 => Lexer.skipValue(trace, in) - case idx => - val field = fieldAliases.getOrElse(aliasesMatrix(idx), -1) - if (buffer(field) != null) - throw UnsafeJson(JsonError.Message("duplicate") :: trace) - else - buffer(field) = schemaDecoder(schemas(field)).unsafeDecode(spans(field) :: trace, in) + val fields = caseClassSchema.fields + val len: Int = fields.length + val buffer = Array.ofDim[Any](len) + val fieldNames = fields.map(_.name.asInstanceOf[String]).toArray + val spans: Array[JsonError] = fields.map(_.name.asInstanceOf[String]).toArray.map(JsonError.ObjectAccess(_)) + val schemas: Array[Schema[_]] = fields.map(_.schema).toArray + val fieldAliases = fields.flatMap { + case Schema.Field(name, _, annotations, _, _, _) => + val aliases = annotations.collectFirst { case a: fieldNameAliases => a.aliases }.getOrElse(Nil) + aliases.map(_ -> fieldNames.indexOf(name)) :+ (name -> fieldNames.indexOf(name)) + }.toMap + val aliasesMatrix = fieldAliases.keys.toArray ++ fieldNames + val rejectExtraFields = caseClassSchema.annotations.collectFirst({ case _: rejectExtraFields => () }).isDefined + + @tailrec + def loop(index: Int, in: RetractReader): Unit = { + val fieldRaw = Lexer.field(trace, in, new StringMatrix(aliasesMatrix)) + if (index == discriminator) { + Lexer.skipValue(trace, in) + } else { + fieldRaw match { + case -1 if index == discriminator => Lexer.skipValue(trace, in) + case -1 if rejectExtraFields => throw UnsafeJson(JsonError.Message("extra field") :: trace) + case -1 => Lexer.skipValue(trace, in) + case idx => + val field = fieldAliases.getOrElse(aliasesMatrix(idx), -1) + if (buffer(field) != null) + throw UnsafeJson(JsonError.Message("duplicate") :: trace) + else + buffer(field) = schemaDecoder(schemas(field)).unsafeDecode(spans(field) :: trace, in) + } + } + if (Lexer.nextField(trace, in)) loop(index + 1, in) } - } - if (Lexer.nextField(trace, in)) loop(index + 1, in) - } - if (discriminator == -1) { - Lexer.char(trace, in, '{') - if (Lexer.firstField(trace, in)) loop(0, in) - } else if (discriminator == -2) { - if (Lexer.nextField(trace, in)) loop(0, in) - } else { - val rr = RecordingReader(in) - if (Lexer.firstField(trace, rr)) loop(0, rr) - } - - var i = 0 - while (i < len) { - if (buffer(i) == null) { - if ((fields(i).optional || fields(i).transient) && fields(i).defaultValue.isDefined) { - buffer(i) = fields(i).defaultValue.get - } else if (config.ignoreEmptyCollections && isCollectionSchema(schemas(i))) { - buffer(i) = createEmptyCollection(schemas(i)) + if (discriminator == -1) { + Lexer.char(trace, in, '{') + if (Lexer.firstField(trace, in)) loop(0, in) + } else if (discriminator == -2) { + if (Lexer.nextField(trace, in)) loop(0, in) } else { - buffer(i) = schemaDecoder(schemas(i)).unsafeDecodeMissing(spans(i) :: trace) + val rr = RecordingReader(in) + if (Lexer.firstField(trace, rr)) loop(0, rr) } + + var i = 0 + while (i < len) { + if (buffer(i) == null) { + if ((fields(i).optional || fields(i).transient) && fields(i).defaultValue.isDefined) { + buffer(i) = fields(i).defaultValue.get + } else if (config.ignoreEmptyCollections && isCollectionSchema(schemas(i))) { + buffer(i) = createEmptyCollection(schemas(i)) + } else { + buffer(i) = schemaDecoder(schemas(i)).unsafeDecodeMissing(spans(i) :: trace) + } + } + i += 1 + } + buffer } - i += 1 - } - buffer -} // Helper method to check if a schema represents a collection type -private def isCollectionSchema(schema: Schema[_]): Boolean = { - schema match { - case Schema.Sequence(_, _, _, _, _) => true - case Schema.Set(_, _) => true - case Schema.Map(_, _, _) => true - case _ => false - } -} - + private def isCollectionSchema(schema: Schema[_]): Boolean = + schema match { + case Schema.Sequence(_, _, _, _, _) => true + case Schema.Set(_, _) => true + case Schema.Map(_, _, _) => true + case _ => false + } // Helper method to create an empty collection based on the schema -private def createEmptyCollection(schema: Schema[_]): Any = { - schema match { - case Schema.Sequence(_, _, _,_,_) => List.empty - case Schema.Set(_, _) => Set.empty - case Schema.Map(_, _,_) => Map.empty - case _ => throw new IllegalArgumentException("Unsupported collection schema") - } -} + private def createEmptyCollection(schema: Schema[_]): Any = + schema match { + case Schema.Sequence(_, _, _, _, _) => List.empty + case Schema.Set(_, _) => Set.empty + case Schema.Map(_, _, _) => Map.empty + case _ => throw new IllegalArgumentException("Unsupported collection schema") + } } diff --git a/zio-schema-json/shared/src/test/scala-2/zio/schema/codec/JsonCodecSpec.scala b/zio-schema-json/shared/src/test/scala-2/zio/schema/codec/JsonCodecSpec.scala index 3ce93e8a5..4c6d0588a 100644 --- a/zio-schema-json/shared/src/test/scala-2/zio/schema/codec/JsonCodecSpec.scala +++ b/zio-schema-json/shared/src/test/scala-2/zio/schema/codec/JsonCodecSpec.scala @@ -1466,7 +1466,10 @@ object JsonCodecSpec extends ZIOSpecDefault { chunk: Chunk[Byte], cfg: JsonCodec.Config = JsonCodec.Config.default ) = { - val result = ZStream.fromChunk(chunk).via(JsonCodec.schemaBasedBinaryCodec[A](cfg)(schema, JsonCodec.Config.default).streamDecoder).runCollect + val result = ZStream + .fromChunk(chunk) + .via(JsonCodec.schemaBasedBinaryCodec[A](cfg)(schema, JsonCodec.Config.default).streamDecoder) + .runCollect assertZIO(result)(equalTo(Chunk(value))) } @@ -1476,13 +1479,22 @@ object JsonCodecSpec extends ZIOSpecDefault { ): ZIO[Any, Nothing, TestResult] = ZStream .succeed(value) - .via(JsonCodec.schemaBasedBinaryCodec[zio.schema.Fallback[A, B]](JsonCodec.Config.default)(schema, JsonCodec.Config.default).streamEncoder) + .via( + JsonCodec + .schemaBasedBinaryCodec[zio.schema.Fallback[A, B]](JsonCodec.Config.default)(schema, JsonCodec.Config.default) + .streamEncoder + ) .runCollect .flatMap { encoded => ZStream .fromChunk(encoded) .via( - JsonCodec.schemaBasedBinaryCodec[zio.schema.Fallback[A, B]](JsonCodec.Config.default)(schema, JsonCodec.Config.default).streamDecoder + JsonCodec + .schemaBasedBinaryCodec[zio.schema.Fallback[A, B]](JsonCodec.Config.default)( + schema, + JsonCodec.Config.default + ) + .streamDecoder ) .runCollect } From 285f97d83ad2cd830f9f4f8d8fdcccb6b1fcc5b2 Mon Sep 17 00:00:00 2001 From: David Anyatonwu Date: Sun, 9 Jun 2024 02:00:50 +0100 Subject: [PATCH 3/4] fix config param not found --- .../test/scala-3/zio/schema/codec/DefaultValueSpec.scala | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/zio-schema-json/shared/src/test/scala-3/zio/schema/codec/DefaultValueSpec.scala b/zio-schema-json/shared/src/test/scala-3/zio/schema/codec/DefaultValueSpec.scala index cd65b6a00..d10300214 100644 --- a/zio-schema-json/shared/src/test/scala-3/zio/schema/codec/DefaultValueSpec.scala +++ b/zio-schema-json/shared/src/test/scala-3/zio/schema/codec/DefaultValueSpec.scala @@ -9,22 +9,23 @@ import zio.test.TestAspect._ import zio.test.* object DefaultValueSpec extends ZIOSpecDefault { + implicit val defaultConfig: JsonCodec.Config = JsonCodec.Config.default def spec: Spec[TestEnvironment, Any] = suite("Custom Spec")( - customSuite, + customSuite ) @@ timeout(90.seconds) private val customSuite = suite("custom")( suite("default value schema")( test("default value at last field") { - val result = JsonCodec.jsonDecoder(Schema[WithDefaultValue]).decodeJson("""{"orderId": 1}""") + val result = JsonCodec.jsonDecoder(Schema[WithDefaultValue], defaultConfig).decodeJson("""{"orderId": 1}""") assertTrue(result.isRight) } ) ) - case class WithDefaultValue(orderId:Int, description: String = "desc") + case class WithDefaultValue(orderId: Int, description: String = "desc") object WithDefaultValue { implicit lazy val schema: Schema[WithDefaultValue] = DeriveSchema.gen[WithDefaultValue] From 5c6f3281f0e5155f64c907057765fafbbad9ba2e Mon Sep 17 00:00:00 2001 From: David Anyatonwu Date: Sun, 9 Jun 2024 02:07:15 +0100 Subject: [PATCH 4/4] fix config param not found --- .../test/scala-3/zio/schema/codec/DefaultValueSpec.scala | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/zio-schema-json/shared/src/test/scala-3/zio/schema/codec/DefaultValueSpec.scala b/zio-schema-json/shared/src/test/scala-3/zio/schema/codec/DefaultValueSpec.scala index d10300214..0aec60878 100644 --- a/zio-schema-json/shared/src/test/scala-3/zio/schema/codec/DefaultValueSpec.scala +++ b/zio-schema-json/shared/src/test/scala-3/zio/schema/codec/DefaultValueSpec.scala @@ -1,12 +1,11 @@ package zio.schema.codec -import zio.Console._ import zio._ import zio.json.{ DeriveJsonEncoder, JsonEncoder } import zio.schema._ import zio.test.Assertion._ import zio.test.TestAspect._ -import zio.test.* +import zio.test._ object DefaultValueSpec extends ZIOSpecDefault { implicit val defaultConfig: JsonCodec.Config = JsonCodec.Config.default @@ -19,7 +18,7 @@ object DefaultValueSpec extends ZIOSpecDefault { private val customSuite = suite("custom")( suite("default value schema")( test("default value at last field") { - val result = JsonCodec.jsonDecoder(Schema[WithDefaultValue], defaultConfig).decodeJson("""{"orderId": 1}""") + val result = JsonCodec.jsonDecoder(Schema[WithDefaultValue]).decodeJson("""{"orderId": 1}""") assertTrue(result.isRight) } ) @@ -30,5 +29,4 @@ object DefaultValueSpec extends ZIOSpecDefault { object WithDefaultValue { implicit lazy val schema: Schema[WithDefaultValue] = DeriveSchema.gen[WithDefaultValue] } - }