Skip to content

Commit

Permalink
feat(avro schema): MultiFormatSchema with Avro
Browse files Browse the repository at this point in the history
  • Loading branch information
Pakisan committed Apr 17, 2024
1 parent 2c630c6 commit 2319ae9
Show file tree
Hide file tree
Showing 589 changed files with 25,044 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.asyncapi.v3.schema.avro.v1._9_0.jackson;

import com.asyncapi.v3.schema.avro.v1._9_0.Avro;
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;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeType;

import java.io.IOException;

public class AvroSchemaDeserializer extends JsonDeserializer<Object> {

@Override
final public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
ObjectCodec objectCodec = p.getCodec();
JsonNode node = objectCodec.readTree(p);

return chooseKnownPojo(node, objectCodec);
}

private Object chooseKnownPojo(JsonNode jsonNode, final ObjectCodec objectCodec) throws IOException {
try (JsonParser jsonParser = jsonNode.traverse(objectCodec)) {
JsonNodeType nodeType = jsonNode.getNodeType();

switch (nodeType) {
case ARRAY:
return readAsUnion((ArrayNode) jsonNode, objectCodec);
case OBJECT:
return jsonParser.readValueAs(Avro.class);
case STRING:
return jsonParser.readValueAs(String.class);
case BOOLEAN:
case NUMBER:
case BINARY:
case POJO:
case MISSING:
case NULL:
return null;
}

return null;
}
}

private AvroUnion readAsUnion(ArrayNode arrayNode, ObjectCodec objectCodec) throws IOException {
AvroUnion avroUnion = new AvroUnion();
for (JsonNode childNode : arrayNode) {
avroUnion.add(chooseKnownPojo(childNode, objectCodec));
}

return avroUnion;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.asyncapi.v3.schema.multiformat;

import com.asyncapi.v3.schema.AsyncAPISchema;
import com.asyncapi.v3.schema.avro.v1._9_0.jackson.AvroSchemaDeserializer;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import lombok.EqualsAndHashCode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
* The Multi Format Schema Object represents a schema definition. It differs from the {@link AsyncAPISchema} in that it supports
* multiple schema formats or languages (e.g., JSON Schema, Avro, etc.).
*
* @see <a href="https://www.asyncapi.com/docs/reference/specification/v3.0.0#multiFormatSchemaObject">Multi Format Schema</a>
* @see <a href="https://www.asyncapi.com/docs/reference/specification/v3.0.0#schemaObject">Schema</a>
* @author Pavel Bodiachevskii
* @version 3.0.0
*/
@EqualsAndHashCode(callSuper = true)
public class AvroFormatSchema extends MultiFormatSchema<Object> {

public AvroFormatSchema(@NotNull @JsonDeserialize(using = AvroSchemaDeserializer.class) Object schema) {
super("application/vnd.apache.avro;version=1.9.0", schema);
}

@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public AvroFormatSchema(
@JsonProperty("schemaFormat") @Nullable String schemaFormat,
@JsonProperty("schema") @NotNull @JsonDeserialize(using = AvroSchemaDeserializer.class) Object schema
) {
super(schemaFormat(schemaFormat), schema);
}

@Override
public void setSchema(@NotNull Object schema) {
super.setSchema(schema);
}

@NotNull
public Object getSchema() {
return super.getSchema();
}

@NotNull
private static String schemaFormat(@Nullable String schemaFormat) {
if (schemaFormat == null || schemaFormat.isEmpty()) {
return "application/vnd.apache.avro;version=1.9.0";
}

return schemaFormat;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,32 @@
"application/vnd.aai.asyncapi;version=3.0.0",
"application/vnd.aai.asyncapi+json;version=3.0.0",
"application/vnd.aai.asyncapi+yaml;version=3.0.0"
}),
@JsonSubTypes.Type(value = AvroFormatSchema.class, names = {
"application/vnd.apache.avro;version=1.9.0",
"application/vnd.apache.avro+json;version=1.9.0",
"application/vnd.apache.avro+yaml;version=1.9.0",
"application/vnd.apache.avro;version=1.9.1",
"application/vnd.apache.avro+json;version=1.9.1",
"application/vnd.apache.avro+yaml;version=1.9.1",
"application/vnd.apache.avro;version=1.9.2",
"application/vnd.apache.avro+json;version=1.9.2",
"application/vnd.apache.avro+yaml;version=1.9.2",
"application/vnd.apache.avro;version=1.10.0",
"application/vnd.apache.avro+json;version=1.10.0",
"application/vnd.apache.avro+yaml;version=1.10.0",
"application/vnd.apache.avro;version=1.10.1",
"application/vnd.apache.avro+json;version=1.10.1",
"application/vnd.apache.avro+yaml;version=1.10.1",
"application/vnd.apache.avro;version=1.10.2",
"application/vnd.apache.avro+json;version=1.10.2",
"application/vnd.apache.avro+yaml;version=1.10.2",
"application/vnd.apache.avro;version=1.11.0",
"application/vnd.apache.avro+json;version=1.11.0",
"application/vnd.apache.avro+yaml;version=1.11.0",
"application/vnd.apache.avro;version=1.11.1",
"application/vnd.apache.avro+json;version=1.11.1",
"application/vnd.apache.avro+yaml;version=1.11.1"
})
})
@EqualsAndHashCode(callSuper = true)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.asyncapi.v3.schema.multiformat

import com.asyncapi.v3.schema.multiformat.asyncapi.*
import com.asyncapi.v3.schema.multiformat.avro.*
import com.asyncapi.v3.schema.multiformat.json.JsonFormatSchemaTest
import com.asyncapi.v3.schema.multiformat.openapi.OpenAPIFormatSchemaV3_0_0Test
import com.asyncapi.v3.schema.multiformat.openapi.OpenAPIFormatSchemaV3_0_1Test
Expand Down Expand Up @@ -60,6 +61,43 @@ class MultiFormatSchemaTest {

}

@Nested
inner class AvroSchema {

@Nested
@DisplayName("1.9.0")
inner class V1_9_0: AvroFormatSchemaV1_9_0Test()

@Nested
@DisplayName("1.9.1")
inner class V1_9_1: AvroFormatSchemaV1_9_1Test()

@Nested
@DisplayName("1.9.2")
inner class V1_9_2: AvroFormatSchemaV1_9_2Test()

@Nested
@DisplayName("1.10.0")
inner class V1_10_0: AvroFormatSchemaV1_10_0Test()

@Nested
@DisplayName("1.10.1")
inner class V1_10_1: AvroFormatSchemaV1_10_1Test()

@Nested
@DisplayName("1.10.2")
inner class V1_10_2: AvroFormatSchemaV1_10_2Test()

@Nested
@DisplayName("1.11.0")
inner class V1_11_0: AvroFormatSchemaV1_11_0Test()

@Nested
@DisplayName("1.11.1")
inner class V1_11_1: AvroFormatSchemaV1_11_1Test()

}

@Nested
inner class JsonSchema {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.asyncapi.v3.schema.multiformat.avro

import com.asyncapi.v3.ClasspathUtils
import com.asyncapi.v3.schema.multiformat.AvroFormatSchema
import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
import org.junit.jupiter.api.Assertions

abstract class AvroFormatSchemaTest {

private val objectMapper: ObjectMapper = ObjectMapper(YAMLFactory())
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
.findAndRegisterModules()

fun compareSchemas(
avroFormatSchemaToCompareWithFilePath: String,
schemaToCheck: AvroFormatSchema
) {
val schemaAsJson = ClasspathUtils.readAsString(avroFormatSchemaToCompareWithFilePath)
val schema = objectMapper.readValue(schemaAsJson, AvroFormatSchema::class.java)

Assertions.assertEquals(schema, schemaToCheck)
}

abstract fun parseJson(
avroFormatSchemaToCompareWithFilePath: String,
avroFormatSchema: AvroFormatSchema
)

abstract fun parseYaml(
avroFormatSchemaToCompareWithFilePath: String,
avroFormatSchema: AvroFormatSchema
)

}
Loading

0 comments on commit 2319ae9

Please sign in to comment.