From 87e7d323462d2ad38bbd313bf5ceba0b55a5521e Mon Sep 17 00:00:00 2001 From: Pavel Bodiachevskii Date: Wed, 17 Apr 2024 01:23:06 +0400 Subject: [PATCH] refactor(avro schema): Avro Union + tests + default for Map and Array https://github.com/asyncapi/jasyncapi/issues/185 --- .../asyncapi/v3/schema/avro/v1/_9_0/Avro.java | 4 + .../v3/schema/avro/v1/_9_0/AvroArray.java | 16 +- .../v3/schema/avro/v1/_9_0/AvroMap.java | 11 +- .../v3/schema/avro/v1/_9_0/AvroUnion.java | 48 ++++ .../v1/_9_0/jackson/AvroTypeDeserializer.java | 13 +- .../v3/schema/avro/AvroSchemasProvider.kt | 251 ++++++++++++------ .../com/asyncapi/v3/schema/avro/AvroTest.kt | 38 +-- 7 files changed, 278 insertions(+), 103 deletions(-) create mode 100644 asyncapi-core/src/main/java/com/asyncapi/v3/schema/avro/v1/_9_0/AvroUnion.java diff --git a/asyncapi-core/src/main/java/com/asyncapi/v3/schema/avro/v1/_9_0/Avro.java b/asyncapi-core/src/main/java/com/asyncapi/v3/schema/avro/v1/_9_0/Avro.java index 3b615cfc..a7f221df 100644 --- a/asyncapi-core/src/main/java/com/asyncapi/v3/schema/avro/v1/_9_0/Avro.java +++ b/asyncapi-core/src/main/java/com/asyncapi/v3/schema/avro/v1/_9_0/Avro.java @@ -23,6 +23,7 @@ use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type", + defaultImpl = AvroUnion.class, visible = true ) @JsonSubTypes({ @@ -65,6 +66,9 @@ public enum LogicalType { @JsonProperty("decimal") DECIMAL, + @JsonProperty("big-decimal") + BIG_DECIMAL, + @JsonProperty("uuid") UUID, diff --git a/asyncapi-core/src/main/java/com/asyncapi/v3/schema/avro/v1/_9_0/AvroArray.java b/asyncapi-core/src/main/java/com/asyncapi/v3/schema/avro/v1/_9_0/AvroArray.java index 8df60659..53b315ba 100644 --- a/asyncapi-core/src/main/java/com/asyncapi/v3/schema/avro/v1/_9_0/AvroArray.java +++ b/asyncapi-core/src/main/java/com/asyncapi/v3/schema/avro/v1/_9_0/AvroArray.java @@ -7,6 +7,9 @@ import lombok.Data; import lombok.EqualsAndHashCode; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; /** * @see Arrays @@ -19,12 +22,19 @@ public AvroArray() { super(AvroType.ARRAY); } + public AvroArray(@NotNull Object items) { + super(AvroType.ARRAY); + this.items = items; + } + @Builder(builderMethodName = "arrayBuilder") public AvroArray( - @NotNull Object items + @NotNull Object items, + @Nullable List defaultValue ) { super(AvroType.ARRAY); this.items = items; + this.defaultValue = defaultValue; } @NotNull @@ -32,6 +42,10 @@ public AvroArray( @JsonDeserialize(using = AvroTypeDeserializer.class) private Object items; + @Nullable + @JsonProperty("default") + private List defaultValue; + @NotNull @Override public AvroType getType() { diff --git a/asyncapi-core/src/main/java/com/asyncapi/v3/schema/avro/v1/_9_0/AvroMap.java b/asyncapi-core/src/main/java/com/asyncapi/v3/schema/avro/v1/_9_0/AvroMap.java index 01a48835..2975cc02 100644 --- a/asyncapi-core/src/main/java/com/asyncapi/v3/schema/avro/v1/_9_0/AvroMap.java +++ b/asyncapi-core/src/main/java/com/asyncapi/v3/schema/avro/v1/_9_0/AvroMap.java @@ -27,8 +27,13 @@ public AvroMap(@NotNull Object values) { } @Builder(builderMethodName = "mapBuilder") - public AvroMap(@NotNull Object values, @Nullable Map metadata) { + public AvroMap( + @NotNull Object values, + @Nullable Map defaultValue, + @Nullable Map metadata + ) { this.values = values; + this.defaultValue = defaultValue; this.metadata = metadata; } @@ -37,6 +42,10 @@ public AvroMap(@NotNull Object values, @Nullable Map metadata) { @JsonDeserialize(using = AvroTypeDeserializer.class) private Object values; + @Nullable + @JsonProperty("default") + private Map defaultValue; + @NotNull @Override public AvroType getType() { diff --git a/asyncapi-core/src/main/java/com/asyncapi/v3/schema/avro/v1/_9_0/AvroUnion.java b/asyncapi-core/src/main/java/com/asyncapi/v3/schema/avro/v1/_9_0/AvroUnion.java new file mode 100644 index 00000000..0f97ec03 --- /dev/null +++ b/asyncapi-core/src/main/java/com/asyncapi/v3/schema/avro/v1/_9_0/AvroUnion.java @@ -0,0 +1,48 @@ +package com.asyncapi.v3.schema.avro.v1._9_0; + +import com.asyncapi.v3.schema.avro.v1._9_0.jackson.AvroTypeDeserializer; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import org.jetbrains.annotations.NotNull; + +import java.util.LinkedList; + +/** + * Avro Union. + *

+ * Unions, as mentioned above, are represented using JSON arrays. + *

+ * For example, ["null", "string"] declares a schema which may be either a null or string. + *

+ *

+ * Note that when a default value is specified for a record field whose type is a union, + * the type of the default value must match the first element of the union. + *

+ * Thus, for unions containing "null", the "null" is usually listed first, + * since the default value of such unions is typically null. + *

+ *

+ * Unions may not contain more than one schema with the same type, except for the named types record, fixed and enum. + *

+ * For example, unions containing two array types or two map types are not permitted, but two types with different names are permitted. + *

+ * (Names permit efficient resolution when reading and writing unions.) + *

+ * Unions may not immediately contain other unions. + * + * @see Unions + * @see Record + */ +@JsonDeserialize(contentUsing = AvroTypeDeserializer.class) +public class AvroUnion extends LinkedList { + + public AvroUnion() { + super(); + } + + public AvroUnion(@NotNull Object variantA, @NotNull Object variantB) { + super(); + add(0, variantA); + add(1, variantB); + } + +} \ No newline at end of file diff --git a/asyncapi-core/src/main/java/com/asyncapi/v3/schema/avro/v1/_9_0/jackson/AvroTypeDeserializer.java b/asyncapi-core/src/main/java/com/asyncapi/v3/schema/avro/v1/_9_0/jackson/AvroTypeDeserializer.java index e8f3fbda..2f2f11f7 100644 --- a/asyncapi-core/src/main/java/com/asyncapi/v3/schema/avro/v1/_9_0/jackson/AvroTypeDeserializer.java +++ b/asyncapi-core/src/main/java/com/asyncapi/v3/schema/avro/v1/_9_0/jackson/AvroTypeDeserializer.java @@ -2,6 +2,7 @@ import com.asyncapi.v3.schema.avro.v1._9_0.Avro; import com.asyncapi.v3.schema.avro.v1._9_0.AvroType; +import com.asyncapi.v3.schema.avro.v1._9_0.AvroUnion; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.ObjectCodec; @@ -12,8 +13,6 @@ import com.fasterxml.jackson.databind.node.JsonNodeType; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; public class AvroTypeDeserializer extends JsonDeserializer { @@ -31,7 +30,7 @@ private Object chooseKnownPojo(JsonNode jsonNode, final ObjectCodec objectCodec) switch (nodeType) { case ARRAY: - return readAsList((ArrayNode) jsonNode, objectCodec); + return readAsUnion((ArrayNode) jsonNode, objectCodec); case BOOLEAN: return jsonNode.asBoolean(); case NUMBER: @@ -51,13 +50,13 @@ private Object chooseKnownPojo(JsonNode jsonNode, final ObjectCodec objectCodec) } } - private List readAsList(ArrayNode arrayNode, ObjectCodec objectCodec) throws IOException { - List list = new ArrayList<>(); + private AvroUnion readAsUnion(ArrayNode arrayNode, ObjectCodec objectCodec) throws IOException { + AvroUnion avroUnion = new AvroUnion(); for (JsonNode childNode : arrayNode) { - list.add(chooseKnownPojo(childNode, objectCodec)); + avroUnion.add(chooseKnownPojo(childNode, objectCodec)); } - return list; + return avroUnion; } } diff --git a/asyncapi-core/src/test/kotlin/com/asyncapi/v3/schema/avro/AvroSchemasProvider.kt b/asyncapi-core/src/test/kotlin/com/asyncapi/v3/schema/avro/AvroSchemasProvider.kt index 67ab9f69..e50678a2 100644 --- a/asyncapi-core/src/test/kotlin/com/asyncapi/v3/schema/avro/AvroSchemasProvider.kt +++ b/asyncapi-core/src/test/kotlin/com/asyncapi/v3/schema/avro/AvroSchemasProvider.kt @@ -22,8 +22,7 @@ class AvroSchemasProvider { .build(), AvroRecordField.builder() .name("documents") - // TODO: union type - .type(listOf( + .type(AvroUnion( AvroType.NULL, AvroArray("model.DocumentInfo") )) @@ -65,8 +64,7 @@ class AvroSchemasProvider { .build(), AvroRecordField.builder() .name("created_at") - // TODO: union type - .type(listOf( + .type(AvroUnion( AvroType.NULL, Avro.builder() .type(AvroType.LONG) @@ -106,15 +104,13 @@ class AvroSchemasProvider { .build(), AvroRecordField.builder() .name("s") - // TODO: union type - .type(listOf( + .type(AvroUnion( AvroType.NULL, AvroType.STRING )) .build(), AvroRecordField.builder() .name("h") - // TODO: union type - .type(listOf( + .type(AvroUnion( AvroType.NULL, AvroType.STRING )) .build() @@ -146,8 +142,7 @@ class AvroSchemasProvider { .build(), AvroRecordField.builder() .name("f32") - // TODO: union type - .type(listOf( + .type(AvroUnion( AvroType.FLOAT, AvroType.NULL )) .build(), @@ -196,8 +191,7 @@ class AvroSchemasProvider { .build(), AvroRecordField.builder() .name("requestId") - // TODO: union type - .type(listOf( + .type(AvroUnion( AvroType.NULL, AvroType.STRING )) .build() @@ -229,8 +223,7 @@ class AvroSchemasProvider { .build(), AvroRecordField.builder() .name("requestId") - // TODO: union type - .type(listOf( + .type(AvroUnion( AvroType.NULL, AvroType.STRING )) .build() @@ -261,16 +254,14 @@ class AvroSchemasProvider { .fields(listOf( AvroRecordField.builder() .name("s") - // TODO: union type - .type(listOf( + .type(AvroUnion( AvroType.NULL, AvroType.STRING )) .defaultValue(null) .build(), AvroRecordField.builder() .name("e") - // TODO: union type - .type(listOf( + .type(AvroUnion( AvroType.NULL, AvroRecord.recordBuilder() .type(AvroType.ERROR) .name("TestError") @@ -314,11 +305,9 @@ class AvroSchemasProvider { .fields(listOf( AvroRecordField.builder() .name("location") - // TODO: union type - .type(listOf( + .type(AvroUnion( AvroType.NULL, AvroMap.mapBuilder() - // TODO: union type - .values(listOf( + .values(AvroUnion( AvroType.NULL, AvroRecord.recordBuilder() .name("r7") @@ -330,8 +319,7 @@ class AvroSchemasProvider { .build(), AvroRecordField.builder() .name("long_r2") - // TODO: union type - .type(listOf(AvroType.NULL, AvroType.FLOAT)) + .type(AvroUnion(AvroType.NULL, AvroType.FLOAT)) .defaultValue(null) .metadata(mapOf(Pair("field-id", 2))) .build() @@ -357,11 +345,9 @@ class AvroSchemasProvider { .fields(listOf( AvroRecordField.builder() .name("location") - // TODO: union type - .type(listOf( + .type(AvroUnion( AvroType.NULL, AvroMap.mapBuilder() - // TODO: union type - .values(listOf( + .values(AvroUnion( AvroType.NULL, AvroRecord.recordBuilder() .name("r7") @@ -373,8 +359,7 @@ class AvroSchemasProvider { .build(), AvroRecordField.builder() .name("long") - // TODO: union type - .type(listOf(AvroType.NULL, AvroType.FLOAT)) + .type(AvroUnion(AvroType.NULL, AvroType.FLOAT)) .defaultValue(null) .metadata(mapOf(Pair("field-id", 2))) .build() @@ -409,14 +394,12 @@ class AvroSchemasProvider { .build(), AvroRecordField.builder() .name("optionalBoolean") - // TODO: union type - .type(listOf(AvroType.NULL, AvroType.BOOLEAN)) + .type(AvroUnion(AvroType.NULL, AvroType.BOOLEAN)) .defaultValue(null) .build(), AvroRecordField.builder() .name("optionalBooleanWithDefault") - // TODO: union type - .type(listOf(AvroType.BOOLEAN, AvroType.NULL)) + .type(AvroUnion(AvroType.BOOLEAN, AvroType.NULL)) .defaultValue(true) .build(), AvroRecordField.builder() @@ -425,14 +408,12 @@ class AvroSchemasProvider { .build(), AvroRecordField.builder() .name("optionalInt") - // TODO: union type - .type(listOf(AvroType.NULL, AvroType.INT)) + .type(AvroUnion(AvroType.NULL, AvroType.INT)) .defaultValue(null) .build(), AvroRecordField.builder() .name("optionalIntWithDefault") - // TODO: union type - .type(listOf(AvroType.INT, AvroType.NULL)) + .type(AvroUnion(AvroType.INT, AvroType.NULL)) .defaultValue(1) .build(), AvroRecordField.builder() @@ -441,14 +422,12 @@ class AvroSchemasProvider { .build(), AvroRecordField.builder() .name("optionalLong") - // TODO: union type - .type(listOf(AvroType.NULL, AvroType.LONG)) + .type(AvroUnion(AvroType.NULL, AvroType.LONG)) .defaultValue(null) .build(), AvroRecordField.builder() .name("optionalLongWithDefault") - // TODO: union type - .type(listOf(AvroType.LONG, AvroType.NULL)) + .type(AvroUnion(AvroType.LONG, AvroType.NULL)) .defaultValue(1) .build(), AvroRecordField.builder() @@ -457,14 +436,12 @@ class AvroSchemasProvider { .build(), AvroRecordField.builder() .name("optionalFloat") - // TODO: union type - .type(listOf(AvroType.NULL, AvroType.FLOAT)) + .type(AvroUnion(AvroType.NULL, AvroType.FLOAT)) .defaultValue(null) .build(), AvroRecordField.builder() .name("optionalFloatWithDefault") - // TODO: union type - .type(listOf(AvroType.FLOAT, AvroType.NULL)) + .type(AvroUnion(AvroType.FLOAT, AvroType.NULL)) .defaultValue(1.0) .build(), AvroRecordField.builder() @@ -473,14 +450,12 @@ class AvroSchemasProvider { .build(), AvroRecordField.builder() .name("optionalDouble") - // TODO: union type - .type(listOf(AvroType.NULL, AvroType.DOUBLE)) + .type(AvroUnion(AvroType.NULL, AvroType.DOUBLE)) .defaultValue(null) .build(), AvroRecordField.builder() .name("optionalDoubleWithDefault") - // TODO: union type - .type(listOf(AvroType.DOUBLE, AvroType.NULL)) + .type(AvroUnion(AvroType.DOUBLE, AvroType.NULL)) .defaultValue(1.0) .build(), AvroRecordField.builder() @@ -489,14 +464,12 @@ class AvroSchemasProvider { .build(), AvroRecordField.builder() .name("optionalBytes") - // TODO: union type - .type(listOf(AvroType.NULL, AvroType.BYTES)) + .type(AvroUnion(AvroType.NULL, AvroType.BYTES)) .defaultValue(null) .build(), AvroRecordField.builder() .name("optionalBytesWithDefault") - // TODO: union type - .type(listOf(AvroType.BYTES, AvroType.NULL)) + .type(AvroUnion(AvroType.BYTES, AvroType.NULL)) .defaultValue("A") .build(), AvroRecordField.builder() @@ -505,14 +478,12 @@ class AvroSchemasProvider { .build(), AvroRecordField.builder() .name("optionalString") - // TODO: union type - .type(listOf(AvroType.NULL, AvroType.STRING)) + .type(AvroUnion(AvroType.NULL, AvroType.STRING)) .defaultValue(null) .build(), AvroRecordField.builder() .name("optionalStringWithDefault") - // TODO: union type - .type(listOf(AvroType.STRING, AvroType.NULL)) + .type(AvroUnion(AvroType.STRING, AvroType.NULL)) .defaultValue("a") .build(), AvroRecordField.builder() @@ -531,8 +502,7 @@ class AvroSchemasProvider { .build(), AvroRecordField.builder() .name("optionalRecord") - // TODO: union type - .type(listOf( + .type(AvroUnion( AvroType.NULL, AvroRecord.recordBuilder() .name("nestedOptionalRecord") .fields(listOf( @@ -547,8 +517,7 @@ class AvroSchemasProvider { .build(), AvroRecordField.builder() .name("optionalRecordWithDefault") - // TODO: union type - .type(listOf( + .type(AvroUnion( AvroRecord.recordBuilder() .name("nestedOptionalRecordWithDefault") .fields(listOf( @@ -572,8 +541,7 @@ class AvroSchemasProvider { .build(), AvroRecordField.builder() .name("optionalEnum") - // TODO: union type - .type(listOf( + .type(AvroUnion( AvroType.NULL, AvroEnum.enumBuilder() .name("optionalEnum") .symbols(listOf("a", "b")) @@ -583,8 +551,7 @@ class AvroSchemasProvider { .build(), AvroRecordField.builder() .name("optionalEnumWithDefault") - // TODO: union type - .type(listOf( + .type(AvroUnion( AvroEnum.enumBuilder() .name("optionalEnumWithDefault") .symbols(listOf("a", "b")) @@ -602,8 +569,7 @@ class AvroSchemasProvider { .build(), AvroRecordField.builder() .name("optionalArray") - // TODO: union type - .type(listOf( + .type(AvroUnion( AvroType.NULL, AvroArray.arrayBuilder() .items(AvroType.STRING) .build() @@ -612,8 +578,7 @@ class AvroSchemasProvider { .build(), AvroRecordField.builder() .name("optionalArrayWithDefault") - // TODO: union type - .type(listOf( + .type(AvroUnion( AvroArray.arrayBuilder() .items(AvroType.STRING) .build(), AvroType.NULL @@ -630,8 +595,7 @@ class AvroSchemasProvider { .build(), AvroRecordField.builder() .name("optionalMap") - // TODO: union type - .type(listOf( + .type(AvroUnion( AvroType.NULL, AvroMap.mapBuilder() .values(AvroType.STRING) .build() @@ -640,8 +604,7 @@ class AvroSchemasProvider { .build(), AvroRecordField.builder() .name("optionalMapWithDefault") - // TODO: union type - .type(listOf( + .type(AvroUnion( AvroMap.mapBuilder() .values(AvroType.STRING) .build(), AvroType.NULL @@ -659,8 +622,7 @@ class AvroSchemasProvider { .build(), AvroRecordField.builder() .name("optionalFixed") - // TODO: union type - .type(listOf( + .type(AvroUnion( AvroType.NULL, AvroFixed.fixedBuilder() .name("optionalFixed") .size(1) @@ -670,8 +632,7 @@ class AvroSchemasProvider { .build(), AvroRecordField.builder() .name("optionalFixedWithDefault") - // TODO: union type - .type(listOf( + .type(AvroUnion( AvroFixed.fixedBuilder() .name("optionalFixedWithDefault") .size(1) @@ -775,4 +736,138 @@ class AvroSchemasProvider { .build() } + fun simpleRecord(): AvroRecord { + return AvroRecord.recordBuilder() + .name("SimpleRecord") + .fields(listOf( + AvroRecordField.builder() + .type(AvroType.INT) + .name("value") + .build(), + AvroRecordField.builder() + .type(AvroUnion(AvroType.NULL, AvroType.INT)) + .name("nullableValue") + .doc("doc") + .build() + )) + .build() + } + + fun testRecordWithLogicalTypes(): AvroRecord { + return AvroRecord.recordBuilder() + .name("TestRecordWithLogicalTypes") + .doc("Schema for TestRecordWithLogicalTypes and TestRecordWithoutLogicalTypes, see TestSpecificLogicalTypes") + .namespace("org.apache.avro.specific") + .fields(listOf( + AvroRecordField.builder() + .type(AvroType.BOOLEAN) + .name("b") + .build(), + AvroRecordField.builder() + .type(AvroType.INT) + .name("i32") + .build(), + AvroRecordField.builder() + .type(AvroType.LONG) + .name("i64") + .build(), + AvroRecordField.builder() + .type(AvroType.FLOAT) + .name("f32") + .build(), + AvroRecordField.builder() + .type(AvroType.DOUBLE) + .name("f64") + .build(), + AvroRecordField.builder() + .type(AvroUnion(AvroType.NULL, AvroType.STRING)) + .name("s") + .defaultValue(null) + .build(), + AvroRecordField.builder() + .type(Avro.builder() + .type(AvroType.INT) + .logicalType(Avro.LogicalType.DATE) + .build() + ) + .name("d") + .build(), + AvroRecordField.builder() + .type(Avro.builder() + .type(AvroType.INT) + .logicalType(Avro.LogicalType.TIME_MILLIS) + .build() + ) + .name("t") + .build(), + AvroRecordField.builder() + .type(Avro.builder() + .type(AvroType.LONG) + .logicalType(Avro.LogicalType.TIMESTAMP_MILLIS) + .build() + ) + .name("ts") + .build(), + AvroRecordField.builder() + .type(Avro.builder() + .type(AvroType.BYTES) + .logicalType(Avro.LogicalType.BIG_DECIMAL) + .build() + ) + .name("bd") + .build(), + )) + .build() + } + + fun testRecordWithMapsAndArrays(): AvroRecord { + return AvroRecord.recordBuilder() + .name("TestRecordWithMapsAndArrays") + .namespace("org.apache.avro.specific") + .fields(listOf( + AvroRecordField.builder() + .name("arr") + .type(AvroArray.arrayBuilder() + .items(AvroType.STRING) + .defaultValue(emptyList()) + .build() + ) + .build(), + AvroRecordField.builder() + .name("map") + .type(AvroMap.mapBuilder() + .values(AvroType.LONG) + .defaultValue(emptyMap()) + .build() + ) + .build() + )) + .build() + } + + fun testUnionRecord(): AvroUnion { + return AvroUnion( + AvroType.NULL, + AvroRecord.recordBuilder() + .name("TestUnionRecord") + .namespace("org.apache.avro.specific") + .fields(listOf( + AvroRecordField.builder() + .name("amount") + .type(AvroUnion( + AvroType.NULL, + Avro.builder() + .type(AvroType.BYTES) + .logicalType(Avro.LogicalType.DECIMAL) + .precision(31) + .scale(8) + .build() + )) + .defaultValue(null) + .build() + )) + .build() + ) + } + } \ No newline at end of file diff --git a/asyncapi-core/src/test/kotlin/com/asyncapi/v3/schema/avro/AvroTest.kt b/asyncapi-core/src/test/kotlin/com/asyncapi/v3/schema/avro/AvroTest.kt index c15e02f0..dc17cd5b 100644 --- a/asyncapi-core/src/test/kotlin/com/asyncapi/v3/schema/avro/AvroTest.kt +++ b/asyncapi-core/src/test/kotlin/com/asyncapi/v3/schema/avro/AvroTest.kt @@ -2,6 +2,7 @@ package com.asyncapi.v3.schema.avro import com.asyncapi.v3.ClasspathUtils import com.asyncapi.v3.schema.avro.v1._9_0.Avro +import com.asyncapi.v3.schema.avro.v1._9_0.AvroUnion import com.fasterxml.jackson.annotation.JsonInclude import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.dataformat.yaml.YAMLFactory @@ -17,10 +18,11 @@ class AvroSchemaTest { fun compareSchemas( schemaToCheckPath: String, - schemaToCheck: Avro + clazz: Class<*>, + schemaToCheck: Any ) { val schemaAsJson = ClasspathUtils.readAsString(schemaToCheckPath) - val schema = objectMapper.readValue(schemaAsJson, Avro::class.java) + val schema = objectMapper.readValue(schemaAsJson, clazz) Assertions.assertEquals(schema, schemaToCheck) } @@ -31,8 +33,8 @@ class AvroSchemaTest { @ArgumentsSource(AvroSchemas::class) @ParameterizedTest(name = "Read: {0}") - fun read(schemaToCheckPath: String, avroSchema: Avro) { - compareSchemas(schemaToCheckPath, avroSchema) + fun read(schemaToCheckPath: String, clazz: Class<*>, avroSchema: Any) { + compareSchemas(schemaToCheckPath, clazz, avroSchema) } class AvroSchemas: ArgumentsProvider { @@ -40,18 +42,22 @@ class AvroSchemaTest { override fun provideArguments(context: ExtensionContext?): Stream { return Stream.of( // Arguments.of("/json/v3/schema/avro/ApplicationEvent.avsc", AvroSchemasProvider().applicationEventTest()), // TODO: fix - Cannot deserialize value of type `com.asyncapi.v3.schema.avro.v1._9_0.AvroSchemaType` from String "model.DocumentInfo" - Arguments.of("/json/v3/schema/avro/DocumentInfo.avsc", AvroSchemasProvider().documentInfo()), - Arguments.of("/json/v3/schema/avro/foo.Bar.avsc", AvroSchemasProvider().fooBar()), - Arguments.of("/json/v3/schema/avro/full_record_v1.avsc", AvroSchemasProvider().fullRecordV1()), - Arguments.of("/json/v3/schema/avro/full_record_v2.avsc", AvroSchemasProvider().fullRecordV2()), - Arguments.of("/json/v3/schema/avro/logical-uuid.avsc", AvroSchemasProvider().logicalUUID()), - Arguments.of("/json/v3/schema/avro/logical_types_with_multiple_fields.avsc", AvroSchemasProvider().logicalTypesWithMultipleFields()), - Arguments.of("/json/v3/schema/avro/MyResponse.avsc", AvroSchemasProvider().myResponse()), - Arguments.of("/json/v3/schema/avro/regression_error_field_in_record.avsc", AvroSchemasProvider().regressionErrorFieldInRecord()), - Arguments.of("/json/v3/schema/avro/schema-location.json", AvroSchemasProvider().schemaLocation()), - Arguments.of("/json/v3/schema/avro/schema-location-read.json", AvroSchemasProvider().schemaLocationRead()), - Arguments.of("/json/v3/schema/avro/schema-location-write.json", AvroSchemasProvider().schemaLocationWrite()), - Arguments.of("/json/v3/schema/avro/SchemaBuilder.avsc", AvroSchemasProvider().schemaBuilder()), + Arguments.of("/json/v3/schema/avro/DocumentInfo.avsc", Avro::class.java, AvroSchemasProvider().documentInfo()), + Arguments.of("/json/v3/schema/avro/foo.Bar.avsc", Avro::class.java, AvroSchemasProvider().fooBar()), + Arguments.of("/json/v3/schema/avro/full_record_v1.avsc", Avro::class.java, AvroSchemasProvider().fullRecordV1()), + Arguments.of("/json/v3/schema/avro/full_record_v2.avsc", Avro::class.java, AvroSchemasProvider().fullRecordV2()), + Arguments.of("/json/v3/schema/avro/logical-uuid.avsc", Avro::class.java, AvroSchemasProvider().logicalUUID()), + Arguments.of("/json/v3/schema/avro/logical_types_with_multiple_fields.avsc", Avro::class.java, AvroSchemasProvider().logicalTypesWithMultipleFields()), + Arguments.of("/json/v3/schema/avro/MyResponse.avsc", Avro::class.java, AvroSchemasProvider().myResponse()), + Arguments.of("/json/v3/schema/avro/regression_error_field_in_record.avsc", Avro::class.java, AvroSchemasProvider().regressionErrorFieldInRecord()), + Arguments.of("/json/v3/schema/avro/schema-location.json", Avro::class.java, AvroSchemasProvider().schemaLocation()), + Arguments.of("/json/v3/schema/avro/schema-location-read.json", Avro::class.java, AvroSchemasProvider().schemaLocationRead()), + Arguments.of("/json/v3/schema/avro/schema-location-write.json", Avro::class.java, AvroSchemasProvider().schemaLocationWrite()), + Arguments.of("/json/v3/schema/avro/SchemaBuilder.avsc", Avro::class.java, AvroSchemasProvider().schemaBuilder()), + Arguments.of("/json/v3/schema/avro/simple_record.avsc", Avro::class.java, AvroSchemasProvider().simpleRecord()), + Arguments.of("/json/v3/schema/avro/TestRecordWithLogicalTypes.avsc", Avro::class.java, AvroSchemasProvider().testRecordWithLogicalTypes()), + Arguments.of("/json/v3/schema/avro/TestRecordWithMapsAndArrays.avsc", Avro::class.java, AvroSchemasProvider().testRecordWithMapsAndArrays()), + Arguments.of("/json/v3/schema/avro/TestUnionRecord.avsc", AvroUnion::class.java, AvroSchemasProvider().testUnionRecord()), ) }