Skip to content

Commit fc247a3

Browse files
authored
Add option to use default case class value during decoding of AvroTransient field (sksamuel#904)
* Add useDefault option to AvroTransient * Remove gpg steps for PR from fork
1 parent 781278b commit fc247a3

6 files changed

Lines changed: 29 additions & 9 deletions

File tree

.github/workflows/pr_scala_3.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,13 @@ jobs:
2828
run: sbt test
2929

3030
- name: Import GPG key
31+
if: github.event.pull_request.head.repo.fork == false
3132
id: import_gpg
3233
uses: crazy-max/ghaction-import-gpg@v3
3334
with:
3435
gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
3536
passphrase: ${{ secrets.PGP_PASSPHRASE }}
3637

3738
- name: publish local
39+
if: github.event.pull_request.head.repo.fork == false
3840
run: sbt publishLocalSigned

avro4s-core/src/main/scala/com/sksamuel/avro4s/annotations.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ trait AvroFixable extends AvroFieldReflection {
6868
*/
6969
case class AvroName(override val name: String) extends AvroNameable
7070

71-
case class AvroTransient() extends StaticAnnotation
71+
case class AvroTransient(useDefault:Boolean=false) extends StaticAnnotation
7272

7373
trait AvroNameable extends AvroFieldReflection {
7474
val name: String

avro4s-core/src/main/scala/com/sksamuel/avro4s/decoders/records.scala

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ class RecordDecoder[T](ctx: magnolia1.CaseClass[Decoder, T]) extends Decoder[T]
1616
val decoders: Array[FieldDecoder[T]] = ctx.params
1717
.map { param =>
1818
val annos = Annotations(param.annotations)
19-
if (annos.transient) TransientFieldDecoder else new SchemaFieldDecoder(param, schema)
19+
annos.transient match {
20+
case Some(useDefault) => TransientFieldDecoder(useDefault, param)
21+
case None => new SchemaFieldDecoder(param, schema)
22+
}
2023
}.toArray
2124
{ t => decodeT(schema, decoders, t) }
2225
}
@@ -48,8 +51,13 @@ trait FieldDecoder[+T] extends Serializable {
4851
/**
4952
* Fields marked with @AvroTransient are always decoded as None's.
5053
*/
51-
object TransientFieldDecoder extends FieldDecoder[Nothing] {
52-
override def decode(record: IndexedRecord): Any = None
54+
case class TransientFieldDecoder[T](useDefault:Boolean, param: magnolia1.CaseClass.Param[Decoder, T]) extends FieldDecoder[Nothing] {
55+
override def decode(record: IndexedRecord): Any = {
56+
if(useDefault)
57+
param.default.get
58+
else
59+
None
60+
}
5361
}
5462

5563
/**

avro4s-core/src/main/scala/com/sksamuel/avro4s/schemas/records.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ object Records:
2424

2525
val fields = ctx.params.toList.flatMap { param =>
2626
val fieldAnnos = Annotations(param.annotations)
27-
if (fieldAnnos.transient) None
27+
if (fieldAnnos.transient.isDefined) None
2828
else {
2929
val doc = fieldAnnos.doc //.orElse(valueTypeDoc).orNull
3030
// val doc = valueTypeDoc(ctx, param)

avro4s-core/src/main/scala/com/sksamuel/avro4s/typeutils/Annotations.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ class Annotations(annos: Seq[Any], inheritedAnnos: Seq[Any] = Nil) {
2727
case t: AvroDocumentable => t.doc
2828
}
2929

30-
def transient: Boolean = annos.collectFirst {
31-
case t: AvroTransient => t
32-
}.isDefined
33-
30+
def transient: Option[Boolean] = annos.collectFirst {
31+
case t: AvroTransient => t.useDefault
32+
}
33+
3434
def erased: Boolean = annos.collectFirst {
3535
case t: AvroErasedName => t
3636
}.isDefined

avro4s-core/src/test/scala/com/sksamuel/avro4s/record/decoder/TransientDecoderTest.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,14 @@ class TransientDecoderTest extends AnyFunSuite with Matchers {
1616
record.put("a", new Utf8("hello"))
1717
Decoder[TransientFoo].decode(schema).apply(record) shouldBe TransientFoo("hello", None)
1818
}
19+
20+
case class Foo(name:String)
21+
case class TransientFooWithDefault(a: String, @AvroTransient(true) b: Foo = Foo("hello"))
22+
23+
test("decoder should populate transient fields with default case class value") {
24+
val schema = AvroSchema[TransientFooWithDefault]
25+
val record = new GenericData.Record(schema)
26+
record.put("a", new Utf8("hello"))
27+
Decoder[TransientFooWithDefault].decode(schema).apply(record) shouldBe TransientFooWithDefault("hello")
28+
}
1929
}

0 commit comments

Comments
 (0)