I'm migrating a Spring Boot application to Quarkus. It's an applications that publishes Kafka messages serialized with Avro.

These are the schemas:

id.avsc

{
  "namespace" : "xxx",
             "type": "record",
             "name": "Id",
             "fields" : [
                 {"name": "prefix", "type": "string"},
                 {"name": "name", "type": "string"}
             ]
}

event.avsc

{
  "namespace" : "yyy",
  "type" : "record",
  "name" : "EventReceived",
  "fields" : [
    {"name":"id", "type": "xxx.Id"},
  ...

The Spring version was able to generate the necessary sources for these Avro types.

The Quarkus app fails with:

Caused by: org.apache.avro.SchemaParseException: "xxx.Id" is not a defined name. The type of the "id" field must be a defined name or a {"type": ...} expression.

How can I reference another Avro type in Quarkus?

build.gradle.kts

plugins {
    kotlin("jvm") version "1.5.31"
    kotlin("plugin.allopen") version "1.5.31"
    id("io.quarkus")
}

repositories {
    mavenCentral()
    maven { url = uri("https://packages.confluent.io/maven") }
    mavenLocal()
}

val quarkusPlatformGroupId: String by project
val quarkusPlatformArtifactId: String by project
val quarkusPlatformVersion: String by project

extra["confluentVersion"] = "7.0.1"

dependencies {
    implementation(enforcedPlatform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}"))
    implementation("io.quarkus:quarkus-resteasy-reactive-jackson")
    implementation("io.quarkus:quarkus-smallrye-opentracing")
    implementation("io.quarkus:quarkus-rest-client-reactive")
    implementation("io.quarkus:quarkus-resteasy-reactive")
    implementation("io.quarkus:quarkus-smallrye-reactive-messaging-kafka")
    implementation("io.quarkus:quarkus-kotlin")
    implementation("io.quarkus:quarkus-avro")
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
    implementation("io.quarkus:quarkus-arc")
    implementation("io.confluent:kafka-avro-serializer:${property("confluentVersion")}")
    testImplementation("io.quarkus:quarkus-junit5")
    testImplementation("io.rest-assured:rest-assured")
}

group = "mygroupid"
version = "1.0-SNAPSHOT"

java {
    sourceCompatibility = JavaVersion.VERSION_11
    targetCompatibility = JavaVersion.VERSION_11
}

allOpen {
    annotation("javax.ws.rs.Path")
    annotation("javax.enterprise.context.ApplicationScoped")
    annotation("io.quarkus.test.junit.QuarkusTest")
}

tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
    kotlinOptions.jvmTarget = JavaVersion.VERSION_11.toString()
    kotlinOptions.javaParameters = true
}

1

There are 1 answers

0
OneCricketeer On

It's not possible for AVSC files to reference each other. My general recommendation for such approaches is to use AVDL files instead, where you can define Java class-like record definitions, rather than as JSON, that can refer to each other, or even import and use external AVSC files.

If you include the Gradle plugin that compiles the schemas into classes, it'll also be able to generate one class per record.

Otherwise, you need to fully embed the record like

"fields": [
  {"type": {
    "type": "record",
    "namespace": "some.package",
    "name": "Id",
    fields: []
  }
]