From dacdbae4e3dbc5a8de2f39f13f5db456ed0d18b3 Mon Sep 17 00:00:00 2001 From: Nabil Abdel-Hafeez <7283535+987Nabil@users.noreply.github.com> Date: Sun, 30 Jun 2024 23:24:51 +0200 Subject: [PATCH] Failing deriving Schemas with transient fields without defaults (#654) --- .../src/main/scala-2/zio/schema/DeriveSchema.scala | 14 +++++++++++--- .../src/main/scala-3/zio/schema/DeriveSchema.scala | 4 ++++ .../scala-2/zio/schema/codec/JsonCodecSpec.scala | 2 +- .../scala-2/zio/schema/codec/ThriftCodecSpec.scala | 2 +- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/zio-schema-derivation/shared/src/main/scala-2/zio/schema/DeriveSchema.scala b/zio-schema-derivation/shared/src/main/scala-2/zio/schema/DeriveSchema.scala index 018079141..9d5d070e4 100644 --- a/zio-schema-derivation/shared/src/main/scala-2/zio/schema/DeriveSchema.scala +++ b/zio-schema-derivation/shared/src/main/scala-2/zio/schema/DeriveSchema.scala @@ -271,10 +271,18 @@ object DeriveSchema { } val hasDefaultAnnotation = annotations.exists { - case q"new _root_.zio.schema.annotation.fieldDefaultValue(..$_)" => true - case _ => false + case ann if ann.toString.contains("new fieldDefaultValue") => true + case _ => false } - if (hasDefaultAnnotation || defaultConstructorValues.get(i).isEmpty) { + val transientField = + annotations.exists { + case ann if ann.toString().endsWith("new transientField()") => true + case _ => false + } + if (transientField && !(hasDefaultAnnotation || defaultConstructorValues.contains(i))) { + throw new IllegalStateException(s"Field ${symbol.name} is transient and must have a default value.") + } + if (hasDefaultAnnotation || !defaultConstructorValues.contains(i)) { annotations } else { annotations :+ diff --git a/zio-schema-derivation/shared/src/main/scala-3/zio/schema/DeriveSchema.scala b/zio-schema-derivation/shared/src/main/scala-3/zio/schema/DeriveSchema.scala index 57df11ebc..e012fbac0 100644 --- a/zio-schema-derivation/shared/src/main/scala-3/zio/schema/DeriveSchema.scala +++ b/zio-schema-derivation/shared/src/main/scala-3/zio/schema/DeriveSchema.scala @@ -339,6 +339,10 @@ private case class DeriveSchema()(using val ctx: Quotes) { .map(_.asExpr.asInstanceOf[Expr[Any]]) val hasDefaultAnnotation = field.annotations.exists(_.tpe <:< TypeRepr.of[zio.schema.annotation.fieldDefaultValue[_]]) + val transientField = field.annotations.exists(_.tpe <:< TypeRepr.of[zio.schema.annotation.transientField]) + if (transientField && !hasDefaultAnnotation && defaults.get(field.name).isEmpty) { + report.errorAndAbort(s"Field ${field.name} is transient and must have a default value.") + } if (hasDefaultAnnotation || defaults.get(field.name).isEmpty) { annos } else { 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 115bee8e5..a74fb7e27 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 @@ -1629,7 +1629,7 @@ object JsonCodecSpec extends ZIOSpecDefault { query: String, pageNumber: Int, resultPerPage: Int, - @transientField nextPage: String + @transientField nextPage: String = "" ) val searchRequestWithTransientFieldSchema: Schema[SearchRequestWithTransientField] = diff --git a/zio-schema-thrift/src/test/scala-2/zio/schema/codec/ThriftCodecSpec.scala b/zio-schema-thrift/src/test/scala-2/zio/schema/codec/ThriftCodecSpec.scala index 5f21af2ca..5067e24f4 100644 --- a/zio-schema-thrift/src/test/scala-2/zio/schema/codec/ThriftCodecSpec.scala +++ b/zio-schema-thrift/src/test/scala-2/zio/schema/codec/ThriftCodecSpec.scala @@ -1169,7 +1169,7 @@ object ThriftCodecSpec extends ZIOSpecDefault { implicit val schema: Schema[PersonWithOptionalField] = DeriveSchema.gen[PersonWithOptionalField] } - case class PersonWithTransientField(name: String, @transientField age: Int) + case class PersonWithTransientField(name: String, @transientField age: Int = 0) object PersonWithTransientField { implicit val schema: Schema[PersonWithTransientField] = DeriveSchema.gen[PersonWithTransientField]