sksamuel / avro4s

Avro schema generation and serialization / deserialization for Scala
Apache License 2.0
719 stars 238 forks source link

improve error message in case of schema mismatch #789

Closed myazinn closed 1 year ago

myazinn commented 1 year ago

currently if you try to decode a case class with field not present in schema, you'll get you a bit useless message like this

[info]   java.lang.NullPointerException: Cannot invoke "org.apache.avro.Schema$Field.schema()" because "field" is null
[info]   at com.sksamuel.avro4s.decoders.SchemaFieldDecoder.<init>(records.scala:64)
[info]   at com.sksamuel.avro4s.decoders.RecordDecoder.$anonfun$1(records.scala:19)
[info]   at scala.collection.ArrayOps$.map$extension(ArrayOps.scala:932)
[info]   at scala.IArray$package$IArray$.map(IArray.scala:179)
[info]   at com.sksamuel.avro4s.decoders.RecordDecoder.decode(records.scala:20)
[info]   at com.sksamuel.avro4s.AvroDataInputStream.$init$$$anonfun$1(AvroDataInputStream.scala:40)
[info]   at scala.Option.map(Option.scala:242)
[info]   at com.sksamuel.avro4s.AvroDataInputStream.<init>(AvroDataInputStream.scala:40)
[info]   at com.sksamuel.avro4s.AvroInputStreamBuilderWithSource.build(AvroInputStream.scala:68)
[info]   at com.sksamuel.avro4s.examples.Examples.f$proxy1$1(Examples.scala:31)

With this MR, the error message should be self-contained to allow finding missing field

[info] - should read back the objects  *** FAILED ***
[info]   com.sksamuel.avro4s.Avro4sDecodingException: Field "caloriess" not found in schema {"type":"record","name":"Pizza","namespace":"com.sksamuel.avro4s.examples.Examples","fields":[{"name":"name","type":"string"},{"name":"ingredients","type":{"type":"array","items":{"type":"record","name":"Ingredient","fields":[{"name":"name","type":"string"},{"name":"sugar","type":"double"},{"name":"fat","type":"double"}]}}},{"name":"vegetarian","type":"boolean"},{"name":"vegan","type":"boolean"},{"name":"calories","type":"int"}]}
[info]   at com.sksamuel.avro4s.decoders.SchemaFieldDecoder.$init$$$anonfun$3(records.scala:65)
[info]   at scala.Option.getOrElse(Option.scala:201)
[info]   at com.sksamuel.avro4s.decoders.SchemaFieldDecoder.<init>(records.scala:65)
[info]   at com.sksamuel.avro4s.decoders.RecordDecoder.$anonfun$1(records.scala:19)
[info]   at scala.collection.ArrayOps$.map$extension(ArrayOps.scala:932)
[info]   at scala.IArray$package$IArray$.map(IArray.scala:179)
[info]   at com.sksamuel.avro4s.decoders.RecordDecoder.decode(records.scala:20)
[info]   at com.sksamuel.avro4s.AvroDataInputStream.$init$$$anonfun$1(AvroDataInputStream.scala:40)
[info]   at scala.Option.map(Option.scala:242)
[info]   at com.sksamuel.avro4s.AvroDataInputStream.<init>(AvroDataInputStream.scala:40)