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..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 @@ -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: @@ -142,13 +143,14 @@ 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 +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 override def run: ZIO[Environment with ZIOAppArgs, Any, Any] = for { @@ -194,8 +197,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 +225,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 +234,14 @@ 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..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,13 +153,14 @@ 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 +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 override def run: ZIO[Environment with ZIOAppArgs, Any, Any] = for { @@ -203,8 +205,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..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,6 +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 val personTransformation: Schema[Person] = PersonDTO.schema.transform[Person]( (dto: PersonDTO) => Person(dto.firstname + " " + dto.lastname, dto.years), @@ -74,20 +75,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..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 @@ -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,9 @@ 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 +685,9 @@ 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,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, _]]): 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]): 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 +984,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 +1013,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 +1021,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 +1099,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 +1122,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 +1146,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 +1171,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 +1197,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 +1224,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 +1252,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 +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]): 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,7 +1313,7 @@ object JsonCodec { } } - private def unsafeDecodeFields[Z](discriminator: Int, trace: List[JsonError], in: RetractReader, caseClassSchema: Schema.Record[Z]) = { + 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) @@ -1355,17 +1362,37 @@ object JsonCodec { var i = 0 while (i < len) { if (buffer(i) == null) { - - if ((fields(i).optional || fields(i).transient) && fields(i).defaultValue.isDefined) + if ((fields(i).optional || fields(i).transient) && fields(i).defaultValue.isDefined) { buffer(i) = fields(i).defaultValue.get - else + } 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 } + +// 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 + } + +// 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..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 @@ -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,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).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).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 +1526,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") 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..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,18 +1,18 @@ 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 def spec: Spec[TestEnvironment, Any] = suite("Custom Spec")( - customSuite, + customSuite ) @@ timeout(90.seconds) private val customSuite = suite("custom")( @@ -24,10 +24,9 @@ object DefaultValueSpec extends ZIOSpecDefault { ) ) - 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] } - }