From 8d60b10e5a14ac63709badde8cd4b58fc7c0da65 Mon Sep 17 00:00:00 2001 From: Steve Etherington Date: Fri, 5 Jan 2024 14:46:50 +0000 Subject: [PATCH] Issue 190 - use fully qualified names for fixed types to handle potential name clashes. --- .../scala/matchers/DefaultParamMatcher.scala | 3 +- .../src/main/scala/matchers/TypeMatcher.scala | 3 +- avrohugger-core/src/test/avro/fixed_two.avsc | 25 ++++++++++++ .../specific/example/fixedtwo/FixedTwo.scala | 40 +++++++++++++++++++ .../specific/example/fixedtwo/one/fixed.scala | 24 +++++++++++ .../specific/example/fixedtwo/two/fixed.scala | 24 +++++++++++ .../specific/example/logical/LogicalSc.scala | 6 +-- .../example/logical/LogicalSc.scala | 2 +- .../standard/example/logical/LogicalSc.scala | 2 +- .../example/shanested/foo/HashRecord.scala | 2 +- .../example/sharecord/HashRecord.scala | 2 +- .../specific/SpecificFileToFileSpec.scala | 18 ++++++++- 12 files changed, 141 insertions(+), 10 deletions(-) create mode 100644 avrohugger-core/src/test/avro/fixed_two.avsc create mode 100644 avrohugger-core/src/test/expected/specific/example/fixedtwo/FixedTwo.scala create mode 100644 avrohugger-core/src/test/expected/specific/example/fixedtwo/one/fixed.scala create mode 100644 avrohugger-core/src/test/expected/specific/example/fixedtwo/two/fixed.scala diff --git a/avrohugger-core/src/main/scala/matchers/DefaultParamMatcher.scala b/avrohugger-core/src/main/scala/matchers/DefaultParamMatcher.scala index 12088ff9..e496c537 100644 --- a/avrohugger-core/src/main/scala/matchers/DefaultParamMatcher.scala +++ b/avrohugger-core/src/main/scala/matchers/DefaultParamMatcher.scala @@ -65,7 +65,8 @@ object DefaultParamMatcher { } case Schema.Type.NULL => NULL case Schema.Type.FIXED => - REF(classStore.generatedClasses(avroSchema)).APPLY(CustomDefaultParamMatcher.checkCustomDecimalType( + val name = RootClass.newClass(s"${avroSchema.getNamespace()}.${classStore.generatedClasses(avroSchema)}") + REF(name).APPLY(CustomDefaultParamMatcher.checkCustomDecimalType( decimalType = typeMatcher.avroScalaTypes.decimal, schema = avroSchema, default = ArrayClass.APPLY())) diff --git a/avrohugger-core/src/main/scala/matchers/TypeMatcher.scala b/avrohugger-core/src/main/scala/matchers/TypeMatcher.scala index acd5a4c4..b0c9ee35 100644 --- a/avrohugger-core/src/main/scala/matchers/TypeMatcher.scala +++ b/avrohugger-core/src/main/scala/matchers/TypeMatcher.scala @@ -68,7 +68,8 @@ class TypeMatcher( default = StringClass) { case UUID => RootClass.newClass(nme.createNameType("java.util.UUID")) } - case Schema.Type.FIXED => classStore.generatedClasses(schema) + case Schema.Type.FIXED => + RootClass.newClass(s"${schema.getNamespace()}.${classStore.generatedClasses(schema)}") case Schema.Type.BYTES => CustomTypeMatcher.checkCustomDecimalType(avroScalaTypes.decimal, schema) case Schema.Type.RECORD => { diff --git a/avrohugger-core/src/test/avro/fixed_two.avsc b/avrohugger-core/src/test/avro/fixed_two.avsc new file mode 100644 index 00000000..14581ff5 --- /dev/null +++ b/avrohugger-core/src/test/avro/fixed_two.avsc @@ -0,0 +1,25 @@ +{ + "type": "record", + "name": "FixedTwo", + "namespace": "fixedtwo", + "fields": [ + { + "name": "first", + "type": { + "type": "fixed", + "name": "fixed", + "namespace": "fixedtwo.one", + "size": 16 + } + }, + { + "name": "second", + "type": { + "type": "fixed", + "name": "fixed", + "namespace": "fixedtwo.two", + "size": 16 + } + } + ] +} diff --git a/avrohugger-core/src/test/expected/specific/example/fixedtwo/FixedTwo.scala b/avrohugger-core/src/test/expected/specific/example/fixedtwo/FixedTwo.scala new file mode 100644 index 00000000..4b4cc076 --- /dev/null +++ b/avrohugger-core/src/test/expected/specific/example/fixedtwo/FixedTwo.scala @@ -0,0 +1,40 @@ +/** MACHINE-GENERATED FROM AVRO SCHEMA. DO NOT EDIT DIRECTLY */ +package fixedtwo + +import scala.annotation.switch + +import fixedtwo.two.fixed + +import fixedtwo.one.fixed + +final case class FixedTwo(var first: fixedtwo.one.fixed, var second: fixedtwo.two.fixed) extends org.apache.avro.specific.SpecificRecordBase { + def this() = this(fixedtwo.one.fixed(Array()), fixedtwo.two.fixed(Array())) + def get(field$: Int): AnyRef = { + (field$: @switch) match { + case 0 => { + first + }.asInstanceOf[AnyRef] + case 1 => { + second + }.asInstanceOf[AnyRef] + case _ => new org.apache.avro.AvroRuntimeException("Bad index") + } + } + def put(field$: Int, value: Any): Unit = { + (field$: @switch) match { + case 0 => this.first = { + value + }.asInstanceOf[fixedtwo.one.fixed] + case 1 => this.second = { + value + }.asInstanceOf[fixedtwo.two.fixed] + case _ => new org.apache.avro.AvroRuntimeException("Bad index") + } + () + } + def getSchema: org.apache.avro.Schema = fixedtwo.FixedTwo.SCHEMA$ +} + +object FixedTwo { + val SCHEMA$ = new org.apache.avro.Schema.Parser().parse("{\"type\":\"record\",\"name\":\"FixedTwo\",\"namespace\":\"fixedtwo\",\"fields\":[{\"name\":\"first\",\"type\":{\"type\":\"fixed\",\"name\":\"fixed\",\"namespace\":\"fixedtwo.one\",\"size\":16}},{\"name\":\"second\",\"type\":{\"type\":\"fixed\",\"name\":\"fixed\",\"namespace\":\"fixedtwo.two\",\"size\":16}}]}") +} \ No newline at end of file diff --git a/avrohugger-core/src/test/expected/specific/example/fixedtwo/one/fixed.scala b/avrohugger-core/src/test/expected/specific/example/fixedtwo/one/fixed.scala new file mode 100644 index 00000000..97935038 --- /dev/null +++ b/avrohugger-core/src/test/expected/specific/example/fixedtwo/one/fixed.scala @@ -0,0 +1,24 @@ +/** MACHINE-GENERATED FROM AVRO SCHEMA. DO NOT EDIT DIRECTLY */ +package fixedtwo.one + +final case class fixed() extends org.apache.avro.specific.SpecificFixed { + def getSchema: org.apache.avro.Schema = fixedtwo.one.fixed.SCHEMA$ + def readExternal(in: java.io.ObjectInput): Unit = { + fixedtwo.one.fixed.READER$.read(this, org.apache.avro.specific.SpecificData.getDecoder(in)) + () + } + def writeExternal(out: java.io.ObjectOutput): Unit = { + fixedtwo.one.fixed.WRITER$.write(this, org.apache.avro.specific.SpecificData.getEncoder(out)) + } +} + +object fixed { + val SCHEMA$ = new org.apache.avro.Schema.Parser().parse("{\"type\":\"fixed\",\"name\":\"fixed\",\"namespace\":\"fixedtwo.one\",\"size\":16}") + val READER$ = new org.apache.avro.specific.SpecificDatumReader[fixed](fixedtwo.one.fixed.SCHEMA$) + val WRITER$ = new org.apache.avro.specific.SpecificDatumWriter[fixed](fixedtwo.one.fixed.SCHEMA$) + def apply(data: Array[Byte]): fixed = { + val fixed = new fixedtwo.one.fixed() + fixed.bytes(data) + fixed + } +} \ No newline at end of file diff --git a/avrohugger-core/src/test/expected/specific/example/fixedtwo/two/fixed.scala b/avrohugger-core/src/test/expected/specific/example/fixedtwo/two/fixed.scala new file mode 100644 index 00000000..21c3a0cc --- /dev/null +++ b/avrohugger-core/src/test/expected/specific/example/fixedtwo/two/fixed.scala @@ -0,0 +1,24 @@ +/** MACHINE-GENERATED FROM AVRO SCHEMA. DO NOT EDIT DIRECTLY */ +package fixedtwo.two + +final case class fixed() extends org.apache.avro.specific.SpecificFixed { + def getSchema: org.apache.avro.Schema = fixedtwo.two.fixed.SCHEMA$ + def readExternal(in: java.io.ObjectInput): Unit = { + fixedtwo.two.fixed.READER$.read(this, org.apache.avro.specific.SpecificData.getDecoder(in)) + () + } + def writeExternal(out: java.io.ObjectOutput): Unit = { + fixedtwo.two.fixed.WRITER$.write(this, org.apache.avro.specific.SpecificData.getEncoder(out)) + } +} + +object fixed { + val SCHEMA$ = new org.apache.avro.Schema.Parser().parse("{\"type\":\"fixed\",\"name\":\"fixed\",\"namespace\":\"fixedtwo.two\",\"size\":16}") + val READER$ = new org.apache.avro.specific.SpecificDatumReader[fixed](fixedtwo.two.fixed.SCHEMA$) + val WRITER$ = new org.apache.avro.specific.SpecificDatumWriter[fixed](fixedtwo.two.fixed.SCHEMA$) + def apply(data: Array[Byte]): fixed = { + val fixed = new fixedtwo.two.fixed() + fixed.bytes(data) + fixed + } +} \ No newline at end of file diff --git a/avrohugger-core/src/test/expected/specific/example/logical/LogicalSc.scala b/avrohugger-core/src/test/expected/specific/example/logical/LogicalSc.scala index dccff297..a93ed041 100644 --- a/avrohugger-core/src/test/expected/specific/example/logical/LogicalSc.scala +++ b/avrohugger-core/src/test/expected/specific/example/logical/LogicalSc.scala @@ -3,8 +3,8 @@ package example.logical import scala.annotation.switch -final case class LogicalSc(var data: BigDecimal, var fxField: fxType, var ts: java.time.Instant, var dt: java.time.LocalDate, var uuid: java.util.UUID, var dataBig: BigDecimal, var tm: java.time.LocalTime, var timeMicros: java.time.LocalTime, var timestampMicros: java.time.ZonedDateTime, var localTimestampMicros: java.time.LocalDateTime, var localTimestampMillis: java.time.LocalDateTime) extends org.apache.avro.specific.SpecificRecordBase { - def this() = this(scala.math.BigDecimal(0), fxType(scala.math.BigDecimal(0)), java.time.Instant.now, java.time.LocalDate.now, java.util.UUID.randomUUID, scala.math.BigDecimal(0), java.time.LocalTime.now, java.time.LocalTime.MIDNIGHT, java.time.ZonedDateTime.of(java.time.LocalDateTime.MIN, java.time.ZoneId.of("UTC")), java.time.LocalDateTime.MIN, java.time.LocalDateTime.MIN) +final case class LogicalSc(var data: BigDecimal, var fxField: example.logical.fxType, var ts: java.time.Instant, var dt: java.time.LocalDate, var uuid: java.util.UUID, var dataBig: BigDecimal, var tm: java.time.LocalTime, var timeMicros: java.time.LocalTime, var timestampMicros: java.time.ZonedDateTime, var localTimestampMicros: java.time.LocalDateTime, var localTimestampMillis: java.time.LocalDateTime) extends org.apache.avro.specific.SpecificRecordBase { + def this() = this(scala.math.BigDecimal(0), example.logical.fxType(scala.math.BigDecimal(0)), java.time.Instant.now, java.time.LocalDate.now, java.util.UUID.randomUUID, scala.math.BigDecimal(0), java.time.LocalTime.now, java.time.LocalTime.MIDNIGHT, java.time.ZonedDateTime.of(java.time.LocalDateTime.MIN, java.time.ZoneId.of("UTC")), java.time.LocalDateTime.MIN, java.time.LocalDateTime.MIN) def get(field$: Int): AnyRef = { (field$: @switch) match { case 0 => { @@ -83,7 +83,7 @@ final case class LogicalSc(var data: BigDecimal, var fxField: fxType, var ts: ja }.asInstanceOf[BigDecimal] case 1 => this.fxField = { value - }.asInstanceOf[fxType] + }.asInstanceOf[example.logical.fxType] case 2 => this.ts = { value match { case (l: Long) => { diff --git a/avrohugger-core/src/test/expected/standard-tagged/example/logical/LogicalSc.scala b/avrohugger-core/src/test/expected/standard-tagged/example/logical/LogicalSc.scala index 1134732f..1c188271 100644 --- a/avrohugger-core/src/test/expected/standard-tagged/example/logical/LogicalSc.scala +++ b/avrohugger-core/src/test/expected/standard-tagged/example/logical/LogicalSc.scala @@ -3,4 +3,4 @@ package example.logical import shapeless.tag.@@ -final case class LogicalSc(data: @@[scala.math.BigDecimal, (shapeless.Nat._9, shapeless.Nat._2)], fxField: fxType, ts: java.time.Instant, dt: java.time.LocalDate, uuid: java.util.UUID, dataBig: @@[scala.math.BigDecimal, ((shapeless.Nat._2, shapeless.Nat._0), (shapeless.Nat._1, shapeless.Nat._2))], tm: java.time.LocalTime, timeMicros: java.time.LocalTime, timestampMicros: java.time.ZonedDateTime, localTimestampMicros: java.time.LocalDateTime, localTimestampMillis: java.time.LocalDateTime) \ No newline at end of file +final case class LogicalSc(data: @@[scala.math.BigDecimal, (shapeless.Nat._9, shapeless.Nat._2)], fxField: example.logical.fxType, ts: java.time.Instant, dt: java.time.LocalDate, uuid: java.util.UUID, dataBig: @@[scala.math.BigDecimal, ((shapeless.Nat._2, shapeless.Nat._0), (shapeless.Nat._1, shapeless.Nat._2))], tm: java.time.LocalTime, timeMicros: java.time.LocalTime, timestampMicros: java.time.ZonedDateTime, localTimestampMicros: java.time.LocalDateTime, localTimestampMillis: java.time.LocalDateTime) \ No newline at end of file diff --git a/avrohugger-core/src/test/expected/standard/example/logical/LogicalSc.scala b/avrohugger-core/src/test/expected/standard/example/logical/LogicalSc.scala index c490a52b..a28868b7 100644 --- a/avrohugger-core/src/test/expected/standard/example/logical/LogicalSc.scala +++ b/avrohugger-core/src/test/expected/standard/example/logical/LogicalSc.scala @@ -1,4 +1,4 @@ /** MACHINE-GENERATED FROM AVRO SCHEMA. DO NOT EDIT DIRECTLY */ package example.logical -final case class LogicalSc(data: BigDecimal, fxField: fxType, ts: java.time.Instant, dt: java.time.LocalDate, uuid: java.util.UUID, dataBig: BigDecimal, tm: java.time.LocalTime, timeMicros: java.time.LocalTime, timestampMicros: java.time.ZonedDateTime, localTimestampMicros: java.time.LocalDateTime, localTimestampMillis: java.time.LocalDateTime) \ No newline at end of file +final case class LogicalSc(data: BigDecimal, fxField: example.logical.fxType, ts: java.time.Instant, dt: java.time.LocalDate, uuid: java.util.UUID, dataBig: BigDecimal, tm: java.time.LocalTime, timeMicros: java.time.LocalTime, timestampMicros: java.time.ZonedDateTime, localTimestampMicros: java.time.LocalDateTime, localTimestampMillis: java.time.LocalDateTime) \ No newline at end of file diff --git a/avrohugger-core/src/test/expected/standard/example/shanested/foo/HashRecord.scala b/avrohugger-core/src/test/expected/standard/example/shanested/foo/HashRecord.scala index 46823567..10ddc8dc 100644 --- a/avrohugger-core/src/test/expected/standard/example/shanested/foo/HashRecord.scala +++ b/avrohugger-core/src/test/expected/standard/example/shanested/foo/HashRecord.scala @@ -3,4 +3,4 @@ package example.shanested.foo import example.shanested.{Prop, Sha256} -final case class HashRecord(my_hash: Sha256, prop: example.shanested.Prop) \ No newline at end of file +final case class HashRecord(my_hash: example.shanested.Sha256, prop: example.shanested.Prop) \ No newline at end of file diff --git a/avrohugger-core/src/test/expected/standard/example/sharecord/HashRecord.scala b/avrohugger-core/src/test/expected/standard/example/sharecord/HashRecord.scala index 6f94d181..73694ad0 100644 --- a/avrohugger-core/src/test/expected/standard/example/sharecord/HashRecord.scala +++ b/avrohugger-core/src/test/expected/standard/example/sharecord/HashRecord.scala @@ -1,4 +1,4 @@ /** MACHINE-GENERATED FROM AVRO SCHEMA. DO NOT EDIT DIRECTLY */ package example.sharecord -final case class HashRecord(my_hash: Sha256) \ No newline at end of file +final case class HashRecord(my_hash: example.sharecord.Sha256) \ No newline at end of file diff --git a/avrohugger-core/src/test/scala/specific/SpecificFileToFileSpec.scala b/avrohugger-core/src/test/scala/specific/SpecificFileToFileSpec.scala index f3f4d237..3e476290 100644 --- a/avrohugger-core/src/test/scala/specific/SpecificFileToFileSpec.scala +++ b/avrohugger-core/src/test/scala/specific/SpecificFileToFileSpec.scala @@ -49,7 +49,8 @@ class SpecificFileToFileSpec extends Specification { correctly generate logical types with custom date, timestamp and time types $e27 correctly generate a protocol with special strings $e28 - correcty generate a simple case class with a wildcarded custom namespace $e29 + correctly generate a simple case class with a wildcarded custom namespace $e29 + correctly handle namespaces for complex types $e30 """ // correctly generate logical types from IDL $e26 @@ -433,4 +434,19 @@ class SpecificFileToFileSpec extends Specification { sourceTrait === util.Util.readFile("avrohugger-core/src/test/expected/specific/example/protocol/Mail.scala") sourceRecord === util.Util.readFile("avrohugger-core/src/test/expected/specific/example/protocol/Message.scala") } + + def e30 = { + val infile = new java.io.File("avrohugger-core/src/test/avro/fixed_two.avsc") + val gen = new Generator(SpecificRecord) + val outDir = gen.defaultOutputDir + "/specific/" + gen.fileToFile(infile, outDir) + + val source1 = util.Util.readFile("target/generated-sources/specific/fixedtwo/FixedTwo.scala") + val source2 = util.Util.readFile("target/generated-sources/specific/fixedtwo/one/fixed.scala") + val source3 = util.Util.readFile("target/generated-sources/specific/fixedtwo/two/fixed.scala") + + source1 === util.Util.readFile("avrohugger-core/src/test/expected/specific/example/fixedtwo/FixedTwo.scala") and + source2 === util.Util.readFile("avrohugger-core/src/test/expected/specific/example/fixedtwo/one/fixed.scala") and + source3 === util.Util.readFile("avrohugger-core/src/test/expected/specific/example/fixedtwo/two/fixed.scala") + } }