Skip to content

Commit

Permalink
Add a better worded exception of unsupported SpecificRecord coder case (
Browse files Browse the repository at this point in the history
#4815)

* Add a better worded exception of unsupported SpecificRecord coder case

* Fix formatting

* Apply review comments
  • Loading branch information
shnapz authored May 25, 2023
1 parent 6db1912 commit 148e34c
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,21 @@ trait AvroCoders {

implicit def avroSpecificRecordCoder[T <: SpecificRecord: ClassTag]: Coder[T] = {
val clazz = ScioUtil.classOf[T]

// Try to get the schema with SpecificData.getSchema
// This relies on private SCHEMA$ field that may not be defined on custom SpecificRecord instance
// Otherwise create a default instance and call getSchema
val schema = Try(SpecificData.get().getSchema(clazz))
.getOrElse(clazz.getDeclaredConstructor().newInstance().getSchema)
// Otherwise create a default instance and call getSchema
.orElse(Try(clazz.getDeclaredConstructor().newInstance().getSchema))
.getOrElse {
val msg =
"Failed to create a coder for SpecificRecord because it is impossible to retrieve an " +
s"Avro schema by instantiating $clazz. Use only a concrete type implementing " +
s"SpecificRecord or use GenericRecord type in your transformations if a concrete " +
s"type is not known in compile time."
throw new RuntimeException(msg)
}

val useReflectApi = true // keep this for backward compatibility
Coder.beam(AvroCoder.of(clazz, schema, useReflectApi))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package com.spotify.scio.coders
import org.scalatest.flatspec.AnyFlatSpec
import com.spotify.scio.testing.CoderAssertions._
import org.apache.avro.generic.GenericRecord
import org.apache.avro.specific.SpecificRecord
import org.scalactic.Equality
import org.scalatest.matchers.should.Matchers

Expand All @@ -29,6 +30,16 @@ final class AvroCoderTest extends AnyFlatSpec with Matchers {
Avro.user coderShould notFallback()
}

it should "support not Avro's SpecificRecord if a concrete type is not provided" in {
val caught = intercept[RuntimeException] {
Avro.user.asInstanceOf[SpecificRecord] coderShould notFallback()
}

caught.getMessage should startWith(
"Failed to create a coder for SpecificRecord because it is impossible to retrieve an Avro"
)
}

it should "support avrohugger generated SpecificRecord" in {
Avro.scalaSpecificAvro coderShould notFallback()
}
Expand Down

0 comments on commit 148e34c

Please sign in to comment.