diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 7e2b4cc06ac85..4a4a60f8b5cd1 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -194,8 +194,7 @@ 2.25.2 1.3.1.Final 1.12.0 - 2.6.13.Final - 0.1.18.Final + 3.1.2 2.0.2 3.7.0 @@ -3928,24 +3927,19 @@ io.apicurio - apicurio-registry-client + apicurio-registry-schema-resolver ${apicurio-registry.version} io.apicurio - apicurio-registry-serdes-avro-serde + apicurio-registry-avro-serde-kafka ${apicurio-registry.version} io.apicurio - apicurio-registry-serdes-jsonschema-serde + apicurio-registry-jsonschema-serde-kafka ${apicurio-registry.version} - - io.apicurio - apicurio-common-rest-client-vertx - ${apicurio-common-rest-client.version} - io.quarkus quarkus-mutiny diff --git a/build-parent/pom.xml b/build-parent/pom.xml index a893c01246b2b..0fc3300b6297c 100644 --- a/build-parent/pom.xml +++ b/build-parent/pom.xml @@ -113,7 +113,7 @@ quay.io/artemiscloud/activemq-artemis-broker:1.0.25 - quay.io/apicurio/apicurio-registry-mem:2.6.13.Final + quay.io/apicurio/apicurio-registry:3.1.4 quay.io/jbosstm/lra-coordinator:latest docker.io/library/rabbitmq:3.12-management docker.io/apachepulsar/pulsar:3.2.4 diff --git a/docs/src/main/asciidoc/apicurio-registry-dev-services.adoc b/docs/src/main/asciidoc/apicurio-registry-dev-services.adoc index 7a539a66901a4..6fa3be349052d 100644 --- a/docs/src/main/asciidoc/apicurio-registry-dev-services.adoc +++ b/docs/src/main/asciidoc/apicurio-registry-dev-services.adoc @@ -17,9 +17,9 @@ This automatic configuration only applies to serializers and deserializers from [source,properties] ---- # for Apicurio Registry serde -mp.messaging.connector.smallrye-kafka.apicurio.registry.url=http://localhost:8081/apis/registry/v2 +mp.messaging.connector.smallrye-kafka.apicurio.registry.url=http://localhost:8081/apis/registry/v3 # for Confluent Schema Registry serde -mp.messaging.connector.smallrye-kafka.schema.registry.url=http://localhost:8081/apis/ccompat/v6 +mp.messaging.connector.smallrye-kafka.schema.registry.url=http://localhost:8081/apis/ccompat/v7 ---- @@ -72,12 +72,12 @@ Note that the Kafka channels in SmallRye Reactive messaging are automatically co == Configuring the image -Dev Services for Apicurio Registry uses `apicurio/apicurio-registry-mem` images. -You can select any 2.x version from https://hub.docker.com/r/apicurio/apicurio-registry-mem: +Dev Services for Apicurio Registry uses `apicurio/apicurio-registry` images. These images use an in-memory h2 database by default. +You can select any 3.x version from https://hub.docker.com/r/apicurio/apicurio-registry: [source,properties,subs=attributes+] ---- -quarkus.apicurio-registry.devservices.image-name={apicurio-registry-image} +quarkus.apicurio-registry.devservices.image-name=apicurio/apicurio-registry:latest-snapshot ---- [[Compose]] diff --git a/docs/src/main/asciidoc/apicurio-registry-v3-migration.adoc b/docs/src/main/asciidoc/apicurio-registry-v3-migration.adoc new file mode 100644 index 0000000000000..f58a550099b00 --- /dev/null +++ b/docs/src/main/asciidoc/apicurio-registry-v3-migration.adoc @@ -0,0 +1,306 @@ +//// +This guide is maintained in the main Quarkus repository +and pull requests should be submitted there: +https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc +//// += Migrating to Apicurio Registry 3.x +include::_attributes.adoc[] +:categories: messaging +:summary: Guide for migrating from Apicurio Registry 2.x to 3.x in Quarkus applications. +:topics: messaging,kafka,apicurio,registry,migration +:extensions: io.quarkus:quarkus-apicurio-registry-avro,io.quarkus:quarkus-messaging-kafka + +This guide covers the migration path from Apicurio Registry 2.x to 3.x for Quarkus applications using Kafka with schema registry serialization. + +IMPORTANT: Apicurio Registry 3.x introduces a **breaking change in schema ID format** from 8-byte (long) to 4-byte (int) identifiers. This affects message compatibility between v2 and v3 producers/consumers. + +== Overview of Changes + +Quarkus has upgraded to Apicurio Registry 3.1.2. This upgrade includes: + +* **New API endpoints**: `/apis/registry/v3` (was `/v2`) +* **New Confluent compatibility endpoint**: `/apis/ccompat/v7` (was `/v6`) +* **Changed schema ID format**: 4-byte integer IDs by default (was 8-byte long) +* **Package restructuring**: Some configuration classes have been renamed +* **New Kiota-based client**: REST client uses Microsoft Kiota for code generation + +== Breaking Changes + +=== Schema ID Format (Critical) + +The most significant breaking change is the schema ID format: + +[cols="1,1,2"] +|=== +|Version |ID Format |ID Handler Class + +|v2.x +|8-byte (long) +|Default behavior (no handler needed) + +|v3.x +|4-byte (int) +|`io.apicurio.registry.serde.Default4ByteIdHandler` +|=== + +Messages produced with v2.x cannot be consumed by v3.x (and vice versa) without explicit configuration. + +=== API Endpoint Changes + +[cols="1,1,1"] +|=== +|Endpoint |v2.x |v3.x + +|Apicurio API +|`/apis/registry/v2` +|`/apis/registry/v3` + +|Confluent Compat +|`/apis/ccompat/v6` +|`/apis/ccompat/v7` +|=== + +The Quarkus Dev Services automatically configures the correct endpoints for v3.x. + +== Migration Scenarios + +=== Scenario 1: New Application (Greenfield) + +For new applications starting fresh with Apicurio Registry 3.x, no special configuration is needed. The default 4-byte schema IDs will be used automatically. + +[source,properties] +---- +# No special configuration required - v3 defaults are used +# Dev Services will start Apicurio Registry 3.x automatically +---- + +=== Scenario 2: Migrating from v2 (No Existing Messages) + +If you are upgrading from v2 but don't have existing messages in Kafka topics that need to be consumed, you can migrate directly to v3 defaults: + +1. Upgrade Quarkus to the version with Apicurio Registry 3.x +2. Clear or recreate your Kafka topics +3. Restart your application - new messages will use 4-byte IDs + +=== Scenario 3: Consuming Existing v2 Messages + +If you need to consume messages that were produced with Apicurio Registry 2.x, configure the `Legacy8ByteIdHandler`: + +[source,properties] +---- +# Configure consumer to read v2 messages with 8-byte schema IDs +mp.messaging.incoming.movies.apicurio.registry.id-handler=io.apicurio.registry.serde.Legacy8ByteIdHandler +---- + +Or configure globally for all channels: + +[source,properties] +---- +# Configure all consumers to use Legacy8ByteIdHandler +mp.messaging.connector.smallrye-kafka.apicurio.registry.id-handler=io.apicurio.registry.serde.Legacy8ByteIdHandler +---- + +=== Scenario 4: Mixed v2/v3 Environment + +During a gradual migration where some services use v2 and others use v3: + +**v3 service consuming from v2 producers:** +[source,properties] +---- +# Consumer reads v2 messages +mp.messaging.incoming.from-v2-service.apicurio.registry.id-handler=io.apicurio.registry.serde.Legacy8ByteIdHandler +---- + +**v3 service producing for v2 consumers:** +[source,properties] +---- +# Producer writes v2-compatible messages +mp.messaging.outgoing.to-v2-service.apicurio.registry.id-handler=io.apicurio.registry.serde.Legacy8ByteIdHandler +---- + +== Configuration Reference + +=== ID Handler Options + +[cols="2,1,3"] +|=== +|Handler Class |ID Size |Use Case + +|`io.apicurio.registry.serde.Default4ByteIdHandler` +|4 bytes +|Default for v3.x, new applications + +|`io.apicurio.registry.serde.Legacy8ByteIdHandler` +|8 bytes +|Backward compatibility with v2.x messages +|=== + +=== Configuration Properties + +[cols="2,3"] +|=== +|Property |Description + +|`apicurio.registry.id-handler` +|Fully qualified class name of the ID handler to use + +|`apicurio.registry.url` +|URL of the Apicurio Registry (auto-configured by Dev Services) + +|`quarkus.apicurio-registry.devservices.image-name` +|Docker image for Dev Services (default: `quay.io/apicurio/apicurio-registry:3.1.2`) +|=== + +=== Per-Channel vs Global Configuration + +**Per-channel configuration:** +[source,properties] +---- +# Incoming channel +mp.messaging.incoming.my-channel.apicurio.registry.id-handler=io.apicurio.registry.serde.Legacy8ByteIdHandler + +# Outgoing channel +mp.messaging.outgoing.my-channel.apicurio.registry.id-handler=io.apicurio.registry.serde.Legacy8ByteIdHandler +---- + +**Global configuration (all channels):** +[source,properties] +---- +mp.messaging.connector.smallrye-kafka.apicurio.registry.id-handler=io.apicurio.registry.serde.Legacy8ByteIdHandler +---- + +== Code Changes + +If you use Apicurio Registry APIs directly in your code, the following changes are required: + +=== Package Renames + +[cols="1,1"] +|=== +|v2 Import |v3 Import + +|`io.apicurio.registry.serde.avro.AvroKafkaSerdeConfig` +|`io.apicurio.registry.serde.avro.AvroSerdeConfig` +|=== + +=== Vertx Setup (Internal/Advanced) + +If you manually configure Vertx for the registry client: + +**v2 code:** +[source,java] +---- +import io.apicurio.registry.resolver.AbstractSchemaResolver; + +AbstractSchemaResolver.setVertx(vertx); +---- + +**v3 code:** +[source,java] +---- +import io.apicurio.registry.resolver.client.RegistryClientFacadeFactory; + +RegistryClientFacadeFactory.vertx = vertx; +---- + +NOTE: Most applications don't need to make this change - Quarkus handles Vertx configuration automatically. + +== Dev Services Configuration + +Dev Services for Apicurio Registry automatically starts a 3.x registry in dev and test modes: + +[source,properties] +---- +# Override the default image if needed +quarkus.apicurio-registry.devservices.image-name=quay.io/apicurio/apicurio-registry:3.1.2 + +# Disable Dev Services if using an external registry +quarkus.apicurio-registry.devservices.enabled=false +---- + +The registry URL is automatically configured: +[source,properties] +---- +# These are set automatically by Dev Services: +mp.messaging.connector.smallrye-kafka.apicurio.registry.url=http://localhost:8081/apis/registry/v3 +mp.messaging.connector.smallrye-kafka.schema.registry.url=http://localhost:8081/apis/ccompat/v7 +---- + +== Testing Both Modes + +To validate that your application works correctly with both v2 and v3 ID formats, you can create tests that explicitly configure each mode: + +[source,java] +---- +@QuarkusTest +public class SchemaRegistryCompatibilityTest { + + @Test + public void testV2CompatibilityMode() { + // Configure Legacy8ByteIdHandler for this test + Map config = new HashMap<>(); + config.put("apicurio.registry.id-handler", + "io.apicurio.registry.serde.Legacy8ByteIdHandler"); + + // Test produce and consume with 8-byte IDs + // ... + } + + @Test + public void testV3NativeMode() { + // Uses default Default4ByteIdHandler + + // Test produce and consume with 4-byte IDs + // ... + } +} +---- + +== Migration Checklist + +Use this checklist when migrating from Apicurio Registry 2.x to 3.x: + +* [ ] Assess existing Kafka topics for v2 messages that need to be consumed +* [ ] Configure `Legacy8ByteIdHandler` for channels consuming v2 messages +* [ ] Update any direct API calls using `AvroKafkaSerdeConfig` to `AvroSerdeConfig` +* [ ] Update any direct API calls using `AbstractSchemaResolver.setVertx()` to `RegistryClientFacadeFactory.vertx` +* [ ] Test consumer compatibility with existing messages +* [ ] Test producer compatibility with downstream consumers +* [ ] Plan topic migration or dual-write strategy if needed + +== Troubleshooting + +=== "Unknown magic byte" Error + +This error indicates a mismatch in schema ID format between producer and consumer: + +[source] +---- +io.apicurio.registry.serde.SerdeException: Unknown magic byte! +---- + +**Solution:** Configure the consumer with the same ID handler used by the producer: +[source,properties] +---- +mp.messaging.incoming.my-channel.apicurio.registry.id-handler=io.apicurio.registry.serde.Legacy8ByteIdHandler +---- + +=== Schema Not Found + +If schemas aren't being found after migration: + +1. Verify the registry URL is correct (`/apis/registry/v3` for v3) +2. Check that the registry container is running (Dev Services should start it automatically) +3. Verify schema compatibility settings in the registry + +=== Verbose CDI Messages + +If you see `Successfully retrieved a Vertx instance from CDI` INFO messages, these are normal but suppressed by default in Quarkus. If they appear, verify your Quarkus version includes the log suppression fix. + +== Additional Resources + +* https://www.apicur.io/registry/docs/apicurio-registry/3.0.x/index.html[Apicurio Registry 3.x Documentation] +* https://www.apicur.io/blog/2025/03/30/migrate-registry-2-to-3[Official Apicurio Migration Guide] +* https://www.apicur.io/blog/2025/04/03/evolving-serialization[Apicurio SerDes Evolution Blog Post] +* xref:kafka-schema-registry-avro.adoc[Using Apache Kafka with Schema Registry and Avro] +* xref:apicurio-registry-dev-services.adoc[Dev Services for Apicurio Registry] diff --git a/docs/src/main/asciidoc/kafka-schema-registry-avro.adoc b/docs/src/main/asciidoc/kafka-schema-registry-avro.adoc index 3bd1e50b4dc34..72272ad0abbb0 100644 --- a/docs/src/main/asciidoc/kafka-schema-registry-avro.adoc +++ b/docs/src/main/asciidoc/kafka-schema-registry-avro.adoc @@ -360,7 +360,7 @@ And run it in JVM mode with: [source, bash] ---- -java -Dmp.messaging.connector.smallrye-kafka.apicurio.registry.url=http://localhost:8081/apis/registry/v2 -jar target/quarkus-app/quarkus-run.jar +java -Dmp.messaging.connector.smallrye-kafka.apicurio.registry.url=http://localhost:8081/apis/registry/v3 -jar target/quarkus-app/quarkus-run.jar ---- NOTE: By default, the application tries to connect to a Kafka broker listening at `localhost:9092`. @@ -370,7 +370,7 @@ Specifying the registry URL on the command line is not very convenient, so you c [source,properties] ---- -%prod.mp.messaging.connector.smallrye-kafka.apicurio.registry.url=http://localhost:8081/apis/registry/v2 +%prod.mp.messaging.connector.smallrye-kafka.apicurio.registry.url=http://localhost:8081/apis/registry/v3 ---- You can build a native executable with: @@ -567,13 +567,13 @@ public class KafkaAndSchemaRegistryTestResource implements QuarkusTestResourceLi @Override public Map start() { kafka.start(); - registry = new GenericContainer<>("apicurio/apicurio-registry-mem:2.4.2.Final") + registry = new GenericContainer<>("apicurio/apicurio-registry:3.0.6") .withExposedPorts(8080) .withEnv("QUARKUS_PROFILE", "prod"); registry.start(); Map properties = new HashMap<>(); properties.put("mp.messaging.connector.smallrye-kafka.apicurio.registry.url", - "http://" + registry.getHost() + ":" + registry.getMappedPort(8080) + "/apis/registry/v2"); + "http://" + registry.getHost() + ":" + registry.getMappedPort(8080) + "/apis/registry/v3"); properties.put("kafka.bootstrap.servers", kafka.getBootstrapServers()); return properties; } @@ -595,116 +595,6 @@ public class MovieResourceTest { } ---- -[[apicurio-versions-compatibility]] -== Using compatible versions of the Apicurio Registry - -The `quarkus-apicurio-registry-avro` extension depends on recent versions of Apicurio Registry client, -and most versions of Apicurio Registry server and client are backwards compatible. -For some you need to make sure that the client used by Serdes is compatible with the server. - -For example, with Apicurio Dev Service if you set the image name to use version `2.1.5.Final`: - -[source,properties] ----- -quarkus.apicurio-registry.devservices.image-name=quay.io/apicurio/apicurio-registry-mem:2.1.5.Final ----- - -You need to make sure that `apicurio-registry-serdes-avro-serde` dependency -and the REST client `apicurio-common-rest-client-vertx` dependency are set to compatible versions: - -[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"] -.pom.xml ----- - - io.quarkus - quarkus-apicurio-registry-avro - - - io.apicurio - apicurio-common-rest-client-vertx - - - io.apicurio - apicurio-registry-serdes-avro-serde - - - - - io.apicurio - apicurio-registry-client - 2.1.5.Final - - - io.apicurio - apicurio-registry-common - 2.1.5.Final - - - io.apicurio - apicurio-registry-serdes-avro-serde - 2.1.5.Final - - - io.apicurio - apicurio-common-rest-client-jdk - - - io.apicurio - apicurio-registry-client - - - io.apicurio - apicurio-registry-common - - - - - io.apicurio - apicurio-common-rest-client-vertx - 0.1.5.Final - ----- - -[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle",subs=attributes+] -.build.gradle ----- -dependencies { - implementation(platform("{quarkus-platform-groupid}:quarkus-bom:2.12.3.Final")) - - ... - - implementation("io.quarkus:quarkus-apicurio-registry-avro") - implementation("io.apicurio:apicurio-registry-serdes-avro-serde") { - exclude group: "io.apicurio", module: "apicurio-common-rest-client-jdk" - exclude group: "io.apicurio", module: "apicurio-registry-client" - exclude group: "io.apicurio", module: "apicurio-registry-common" - version { - strictly "2.1.5.Final" - } - } - implementation("io.apicurio:apicurio-registry-client") { - version { - strictly "2.1.5.Final" - } - } - implementation("io.apicurio:apicurio-registry-common") { - version { - strictly "2.1.5.Final" - } - } - implementation("io.apicurio:apicurio-common-rest-client-vertx") { - version { - strictly "0.1.5.Final" - } - } -} ----- - -Known previous compatible versions for `apicurio-registry-client` and `apicurio-common-rest-client-vertx` are the following - -- `apicurio-registry-client` 2.1.5.Final with `apicurio-common-rest-client-vertx` 0.1.5.Final -- `apicurio-registry-client` 2.3.1.Final with `apicurio-common-rest-client-vertx` 0.1.13.Final - [[confluent]] == Using the Confluent Schema Registry diff --git a/docs/src/main/asciidoc/kafka-schema-registry-json-schema.adoc b/docs/src/main/asciidoc/kafka-schema-registry-json-schema.adoc index b37e194345c11..fb25aef4096ab 100644 --- a/docs/src/main/asciidoc/kafka-schema-registry-json-schema.adoc +++ b/docs/src/main/asciidoc/kafka-schema-registry-json-schema.adoc @@ -388,7 +388,7 @@ And run it in JVM mode with: [source, bash] ---- -java -Dmp.messaging.connector.smallrye-kafka.apicurio.registry.url=http://localhost:8081/apis/registry/v2 -jar target/quarkus-app/quarkus-run.jar +java -Dmp.messaging.connector.smallrye-kafka.apicurio.registry.url=http://localhost:8081/apis/registry/v3 -jar target/quarkus-app/quarkus-run.jar ---- NOTE: By default, the application tries to connect to a Kafka broker listening at `localhost:9092`. @@ -398,7 +398,7 @@ Specifying the registry URL on the command line is not very convenient, so you c [source,properties] ---- -%prod.mp.messaging.connector.smallrye-kafka.apicurio.registry.url=http://localhost:8081/apis/registry/v2 +%prod.mp.messaging.connector.smallrye-kafka.apicurio.registry.url=http://localhost:8081/apis/registry/v3 ---- You can build a native executable with: @@ -595,13 +595,13 @@ public class KafkaAndSchemaRegistryTestResource implements QuarkusTestResourceLi @Override public Map start() { kafka.start(); - registry = new GenericContainer<>("apicurio/apicurio-registry-mem:2.4.2.Final") + registry = new GenericContainer<>("apicurio/apicurio-registry:3.0.6") .withExposedPorts(8080) .withEnv("QUARKUS_PROFILE", "prod"); registry.start(); Map properties = new HashMap<>(); properties.put("mp.messaging.connector.smallrye-kafka.apicurio.registry.url", - "http://" + registry.getHost() + ":" + registry.getMappedPort(8080) + "/apis/registry/v2"); + "http://" + registry.getHost() + ":" + registry.getMappedPort(8080) + "/apis/registry/v3"); properties.put("kafka.bootstrap.servers", kafka.getBootstrapServers()); return properties; } @@ -623,116 +623,6 @@ public class MovieResourceTest { } ---- -[[apicurio-versions-compatibility]] -== Using compatible versions of the Apicurio Registry - -The `quarkus-apicurio-registry-json-schema` extension depends on recent versions of Apicurio Registry client, -and most versions of Apicurio Registry server and client are backwards compatible. -For some you need to make sure that the client used by Serdes is compatible with the server. - -For example, with Apicurio Dev Service if you set the image name to use version `2.1.5.Final`: - -[source,properties] ----- -quarkus.apicurio-registry.devservices.image-name=quay.io/apicurio/apicurio-registry-mem:2.1.5.Final ----- - -You need to make sure that `apicurio-registry-serdes-json-schema-serde` dependency -and the REST client `apicurio-common-rest-client-vertx` dependency are set to compatible versions: - -[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"] -.pom.xml ----- - - io.quarkus - quarkus-apicurio-registry-json-schema - - - io.apicurio - apicurio-common-rest-client-vertx - - - io.apicurio - apicurio-registry-serdes-json-schema-serde - - - - - io.apicurio - apicurio-registry-client - 2.1.5.Final - - - io.apicurio - apicurio-registry-common - 2.1.5.Final - - - io.apicurio - apicurio-registry-serdes-json-schema-serde - 2.1.5.Final - - - io.apicurio - apicurio-common-rest-client-jdk - - - io.apicurio - apicurio-registry-client - - - io.apicurio - apicurio-registry-common - - - - - io.apicurio - apicurio-common-rest-client-vertx - 0.1.5.Final - ----- - -[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle",subs=attributes+] -.build.gradle ----- -dependencies { - implementation(platform("{quarkus-platform-groupid}:quarkus-bom:2.12.3.Final")) - - ... - - implementation("io.quarkus:quarkus-apicurio-registry-json-schema") - implementation("io.apicurio:apicurio-registry-serdes-json-schema-serde") { - exclude group: "io.apicurio", module: "apicurio-common-rest-client-jdk" - exclude group: "io.apicurio", module: "apicurio-registry-client" - exclude group: "io.apicurio", module: "apicurio-registry-common" - version { - strictly "2.1.5.Final" - } - } - implementation("io.apicurio:apicurio-registry-client") { - version { - strictly "2.1.5.Final" - } - } - implementation("io.apicurio:apicurio-registry-common") { - version { - strictly "2.1.5.Final" - } - } - implementation("io.apicurio:apicurio-common-rest-client-vertx") { - version { - strictly "0.1.5.Final" - } - } -} ----- - -Known previous compatible versions for `apicurio-registry-client` and `apicurio-common-rest-client-vertx` are the following - -- `apicurio-registry-client` 2.1.5.Final with `apicurio-common-rest-client-vertx` 0.1.5.Final -- `apicurio-registry-client` 2.3.1.Final with `apicurio-common-rest-client-vertx` 0.1.13.Final - [[confluent]] == Using the Confluent Schema Registry diff --git a/docs/src/main/asciidoc/kafka.adoc b/docs/src/main/asciidoc/kafka.adoc index c95e632558728..b49db919c3e82 100644 --- a/docs/src/main/asciidoc/kafka.adoc +++ b/docs/src/main/asciidoc/kafka.adoc @@ -3437,11 +3437,11 @@ Then, you can configure the Quarkus application to connect to the schema registr [source, properties] ---- mp.messaging.connector.smallrye-kafka.apicurio.registry.url=${RHOAS_SERVICE_REGISTRY_URL} <1> -mp.messaging.connector.smallrye-kafka.apicurio.auth.service.token.endpoint=${RHOAS_OAUTH_TOKEN_ENDPOINT} <2> -mp.messaging.connector.smallrye-kafka.apicurio.auth.client.id=${RHOAS_CLIENT_ID} <3> -mp.messaging.connector.smallrye-kafka.apicurio.auth.client.secret=${RHOAS_CLIENT_ID} <4> +mp.messaging.connector.smallrye-kafka.apicurio.registry.auth.service.token.endpoint=${RHOAS_OAUTH_TOKEN_ENDPOINT} <2> +mp.messaging.connector.smallrye-kafka.apicurio.registry.auth.client.id=${RHOAS_CLIENT_ID} <3> +mp.messaging.connector.smallrye-kafka.apicurio.registry.auth.client.secret=${RHOAS_CLIENT_ID} <4> ---- -<1> The service registry URL, given on the admin console, such as `https://bu98.serviceregistry.rhcloud.com/t/0e95af2c-6e11-475e-82ee-f13bd782df24/apis/registry/v2` +<1> The service registry URL, given on the admin console, such as `https://bu98.serviceregistry.rhcloud.com/t/0e95af2c-6e11-475e-82ee-f13bd782df24/apis/registry/v3` <2> The OAuth token endpoint URL, such as `https://identity.api.openshift.com/auth/realms/rhoas/protocol/openid-connect/token` <3> The client id (from the service account) <4> The client secret (from the service account) diff --git a/extensions/kafka-client/deployment/src/main/java/io/quarkus/kafka/client/deployment/KafkaProcessor.java b/extensions/kafka-client/deployment/src/main/java/io/quarkus/kafka/client/deployment/KafkaProcessor.java index d641c09a531f2..295ec7ba33aa4 100644 --- a/extensions/kafka-client/deployment/src/main/java/io/quarkus/kafka/client/deployment/KafkaProcessor.java +++ b/extensions/kafka-client/deployment/src/main/java/io/quarkus/kafka/client/deployment/KafkaProcessor.java @@ -385,14 +385,14 @@ private void handleAvro(BuildProducer reflectiveClass, if (QuarkusClassLoader.isClassPresentAtRuntime("io.apicurio.registry.serde.avro.AvroKafkaDeserializer") && !capabilities.isPresent(Capability.APICURIO_REGISTRY_AVRO)) { throw new RuntimeException( - "Apicurio Registry 2.x Avro classes detected, please use the quarkus-apicurio-registry-avro extension"); + "Apicurio Registry 3.x Avro classes detected, please use the quarkus-apicurio-registry-avro extension"); } // --- Apicurio Registry 2.x Json Schema --- if (QuarkusClassLoader.isClassPresentAtRuntime("io.apicurio.registry.serde.avro.JsonKafkaDeserializer") && !capabilities.isPresent(Capability.APICURIO_REGISTRY_JSON_SCHEMA)) { throw new RuntimeException( - "Apicurio Registry 2.x Json classes detected, please use the quarkus-apicurio-registry-json extension"); + "Apicurio Registry 3.x Json classes detected, please use the quarkus-apicurio-registry-json extension"); } } diff --git a/extensions/schema-registry/apicurio/avro/deployment/src/main/java/io/quarkus/apicurio/registry/avro/ApicurioRegistryAvroProcessor.java b/extensions/schema-registry/apicurio/avro/deployment/src/main/java/io/quarkus/apicurio/registry/avro/ApicurioRegistryAvroProcessor.java index 1a5bb9aba25a7..c638dd79c94c7 100644 --- a/extensions/schema-registry/apicurio/avro/deployment/src/main/java/io/quarkus/apicurio/registry/avro/ApicurioRegistryAvroProcessor.java +++ b/extensions/schema-registry/apicurio/avro/deployment/src/main/java/io/quarkus/apicurio/registry/avro/ApicurioRegistryAvroProcessor.java @@ -1,6 +1,5 @@ package io.quarkus.apicurio.registry.avro; -import io.quarkus.bootstrap.classloading.QuarkusClassLoader; import io.quarkus.deployment.Feature; import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.annotations.BuildStep; @@ -29,18 +28,11 @@ public void apicurioRegistryAvro(BuildProducer reflect "io.apicurio.registry.serde.avro.strategy.TopicRecordIdStrategy").methods().fields() .build()); - reflectiveClass.produce(ReflectiveClassBuildItem.builder("io.apicurio.registry.serde.DefaultIdHandler", - "io.apicurio.registry.serde.Legacy4ByteIdHandler", + reflectiveClass.produce(ReflectiveClassBuildItem.builder("io.apicurio.registry.serde.Default4ByteIdHandler", + "io.apicurio.registry.serde.Legacy8ByteIdHandler", "io.apicurio.registry.serde.fallback.DefaultFallbackArtifactProvider", "io.apicurio.registry.serde.headers.DefaultHeadersHandler").methods().fields() .build()); - - String defaultSchemaResolver = "io.apicurio.registry.serde.DefaultSchemaResolver"; - if (QuarkusClassLoader.isClassPresentAtRuntime(defaultSchemaResolver)) { - // Class not present after 2.2.0.Final - reflectiveClass.produce(ReflectiveClassBuildItem.builder(defaultSchemaResolver).methods() - .fields().build()); - } } @BuildStep diff --git a/extensions/schema-registry/apicurio/avro/runtime/pom.xml b/extensions/schema-registry/apicurio/avro/runtime/pom.xml index f3d8fa5e3438c..e02d3a2d8d197 100644 --- a/extensions/schema-registry/apicurio/avro/runtime/pom.xml +++ b/extensions/schema-registry/apicurio/avro/runtime/pom.xml @@ -17,13 +17,7 @@ io.apicurio - apicurio-registry-serdes-avro-serde - - - io.apicurio - apicurio-common-rest-client-jdk - - + apicurio-registry-avro-serde-kafka diff --git a/extensions/schema-registry/apicurio/common/deployment/src/main/java/io/quarkus/apicurio/registry/common/ApicurioRegistryClientProcessor.java b/extensions/schema-registry/apicurio/common/deployment/src/main/java/io/quarkus/apicurio/registry/common/ApicurioRegistryClientProcessor.java index bb74ef643ac1c..546fa4c296415 100644 --- a/extensions/schema-registry/apicurio/common/deployment/src/main/java/io/quarkus/apicurio/registry/common/ApicurioRegistryClientProcessor.java +++ b/extensions/schema-registry/apicurio/common/deployment/src/main/java/io/quarkus/apicurio/registry/common/ApicurioRegistryClientProcessor.java @@ -1,45 +1,18 @@ package io.quarkus.apicurio.registry.common; -import java.io.IOException; +import java.util.logging.Level; -import io.apicurio.rest.client.spi.ApicurioHttpClientProvider; import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.annotations.BuildStep; import io.quarkus.deployment.annotations.ExecutionTime; import io.quarkus.deployment.annotations.Record; -import io.quarkus.deployment.builditem.ExtensionSslNativeSupportBuildItem; import io.quarkus.deployment.builditem.LaunchModeBuildItem; -import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; -import io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem; +import io.quarkus.deployment.builditem.LogCategoryBuildItem; import io.quarkus.smallrye.openapi.deployment.spi.IgnoreStaticDocumentBuildItem; import io.quarkus.vertx.deployment.VertxBuildItem; public class ApicurioRegistryClientProcessor { - @BuildStep - public void apicurioRegistryClient(BuildProducer reflectiveClass, - BuildProducer sslNativeSupport) { - reflectiveClass - .produce(ReflectiveClassBuildItem.builder("io.apicurio.rest.client.auth.exception.NotAuthorizedException", - "io.apicurio.rest.client.auth.exception.ForbiddenException", - "io.apicurio.rest.client.auth.exception.AuthException", - "io.apicurio.rest.client.auth.exception.AuthErrorHandler", - "io.apicurio.rest.client.auth.request.TokenRequestsProvider", - "io.apicurio.rest.client.request.Request", - "io.apicurio.rest.client.auth.AccessTokenResponse", - "io.apicurio.rest.client.auth.Auth", - "io.apicurio.rest.client.auth.BasicAuth", - "io.apicurio.rest.client.auth.OidcAuth").methods().fields().build()); - } - - @BuildStep - void registerSPIClient(BuildProducer services) throws IOException { - - services.produce( - new ServiceProviderBuildItem(ApicurioHttpClientProvider.class.getName(), - "io.apicurio.rest.client.VertxHttpClientProvider")); - } - @BuildStep void ignoreIncludedOpenAPIDocument(BuildProducer ignoreStaticDocumentProducer) { // This will ignore the OpenAPI Document in META-INF/openapi.yaml in the apicurio-registry-common dependency @@ -47,6 +20,13 @@ void ignoreIncludedOpenAPIDocument(BuildProducer ".*/io/apicurio/apicurio-registry-common/.*/apicurio-registry-common-.*.jar.*")); } + @BuildStep + void logging(BuildProducer log) { + // Reduce the log level of Apicurio Registry client to avoid verbose INFO messages + // See https://github.com/quarkusio/quarkus/issues/51008 + log.produce(new LogCategoryBuildItem("io.apicurio.registry.client", Level.WARNING)); + } + @BuildStep @Record(ExecutionTime.RUNTIME_INIT) public void apicurioRegistryClient(VertxBuildItem vertx, ApicurioRegistryClient client, LaunchModeBuildItem launchMode) { diff --git a/extensions/schema-registry/apicurio/common/deployment/src/test/java/io/quarkus/apicurio/registry/common/ApicurioRegistryInternalsExpectationTest.java b/extensions/schema-registry/apicurio/common/deployment/src/test/java/io/quarkus/apicurio/registry/common/ApicurioRegistryInternalsExpectationTest.java index ab2da367a32d8..9d3e2f37ccd86 100644 --- a/extensions/schema-registry/apicurio/common/deployment/src/test/java/io/quarkus/apicurio/registry/common/ApicurioRegistryInternalsExpectationTest.java +++ b/extensions/schema-registry/apicurio/common/deployment/src/test/java/io/quarkus/apicurio/registry/common/ApicurioRegistryInternalsExpectationTest.java @@ -2,12 +2,9 @@ import org.junit.jupiter.api.Test; -import io.apicurio.rest.client.spi.ApicurioHttpClientFactory; - public class ApicurioRegistryInternalsExpectationTest { @Test public void test() throws NoSuchFieldException { // we need this to reset the client in continuous testing - ApicurioHttpClientFactory.class.getDeclaredField("providerReference"); } } diff --git a/extensions/schema-registry/apicurio/common/runtime/pom.xml b/extensions/schema-registry/apicurio/common/runtime/pom.xml index 5e04248f4f574..edbc13675e238 100644 --- a/extensions/schema-registry/apicurio/common/runtime/pom.xml +++ b/extensions/schema-registry/apicurio/common/runtime/pom.xml @@ -17,17 +17,7 @@ io.apicurio - apicurio-registry-client - - - io.apicurio - apicurio-common-rest-client-jdk - - - - - io.apicurio - apicurio-common-rest-client-vertx + apicurio-registry-schema-resolver org.apache.commons diff --git a/extensions/schema-registry/apicurio/common/runtime/src/main/java/io/quarkus/apicurio/registry/binding/ServiceRegistryBindingConverter.java b/extensions/schema-registry/apicurio/common/runtime/src/main/java/io/quarkus/apicurio/registry/binding/ServiceRegistryBindingConverter.java index 13914a24db994..14dffd02b9e6e 100644 --- a/extensions/schema-registry/apicurio/common/runtime/src/main/java/io/quarkus/apicurio/registry/binding/ServiceRegistryBindingConverter.java +++ b/extensions/schema-registry/apicurio/common/runtime/src/main/java/io/quarkus/apicurio/registry/binding/ServiceRegistryBindingConverter.java @@ -53,7 +53,7 @@ public Optional convert(List service oauthTokenUrl = binding.getProperties().get("oauthtokenurl"); } if (oauthTokenUrl != null) { - properties.put(prefix + "apicurio.auth.service.token.endpoint", oauthTokenUrl); + properties.put(prefix + "apicurio.registry.auth.service.token.endpoint", oauthTokenUrl); } String clientId = binding.getProperties().get("clientId"); @@ -61,7 +61,7 @@ public Optional convert(List service clientId = binding.getProperties().get("clientid"); } if (clientId != null) { - properties.put(prefix + "apicurio.auth.client.id", clientId); + properties.put(prefix + "apicurio.registry.auth.client.id", clientId); } String clientSecret = binding.getProperties().get("clientSecret"); @@ -69,7 +69,7 @@ public Optional convert(List service clientSecret = binding.getProperties().get("clientsecret"); } if (clientSecret != null) { - properties.put(prefix + "apicurio.auth.client.secret", clientSecret); + properties.put(prefix + "apicurio.registry.auth.client.secret", clientSecret); } if (registryUrl != null) { properties.put(prefix + "apicurio.registry.url", registryUrl); diff --git a/extensions/schema-registry/apicurio/common/runtime/src/main/java/io/quarkus/apicurio/registry/common/ApicurioRegistryClient.java b/extensions/schema-registry/apicurio/common/runtime/src/main/java/io/quarkus/apicurio/registry/common/ApicurioRegistryClient.java index 80a544a63979c..9ec4e10b8951f 100644 --- a/extensions/schema-registry/apicurio/common/runtime/src/main/java/io/quarkus/apicurio/registry/common/ApicurioRegistryClient.java +++ b/extensions/schema-registry/apicurio/common/runtime/src/main/java/io/quarkus/apicurio/registry/common/ApicurioRegistryClient.java @@ -1,13 +1,8 @@ package io.quarkus.apicurio.registry.common; -import java.lang.reflect.Field; -import java.util.concurrent.atomic.AtomicReference; - import org.jboss.logging.Logger; -import io.apicurio.registry.rest.client.RegistryClientFactory; -import io.apicurio.rest.client.VertxHttpClientProvider; -import io.apicurio.rest.client.spi.ApicurioHttpClientFactory; +import io.apicurio.registry.resolver.client.RegistryClientFacadeFactory; import io.quarkus.runtime.RuntimeValue; import io.quarkus.runtime.annotations.Recorder; import io.vertx.core.Vertx; @@ -18,17 +13,14 @@ public class ApicurioRegistryClient { private static final Logger log = Logger.getLogger(ApicurioRegistryClient.class); public void setup(RuntimeValue vertx) { - RegistryClientFactory.setProvider(new VertxHttpClientProvider(vertx.getValue())); + RegistryClientFacadeFactory.vertx = vertx.getValue(); } public void clearHttpClient() { try { - Field providerReference = ApicurioHttpClientFactory.class.getDeclaredField("providerReference"); - providerReference.setAccessible(true); - AtomicReference ref = (AtomicReference) providerReference.get(null); - ref.set(null); - } catch (NoSuchFieldException | IllegalAccessException t) { - log.error("Failed to clear Apicurio Http Client provider", t); + RegistryClientFacadeFactory.vertx = null; + } catch (Exception t) { + log.error("Failed to clear Apicurio Http Client", t); } } -} \ No newline at end of file +} diff --git a/extensions/schema-registry/apicurio/json-schema/deployment/src/main/java/io/quarkus/apicurio/registry/jsonschema/ApicurioRegistryJsonSchemaProcessor.java b/extensions/schema-registry/apicurio/json-schema/deployment/src/main/java/io/quarkus/apicurio/registry/jsonschema/ApicurioRegistryJsonSchemaProcessor.java index 83c6f0886bba9..6b51932a8ca5e 100644 --- a/extensions/schema-registry/apicurio/json-schema/deployment/src/main/java/io/quarkus/apicurio/registry/jsonschema/ApicurioRegistryJsonSchemaProcessor.java +++ b/extensions/schema-registry/apicurio/json-schema/deployment/src/main/java/io/quarkus/apicurio/registry/jsonschema/ApicurioRegistryJsonSchemaProcessor.java @@ -1,6 +1,5 @@ package io.quarkus.apicurio.registry.jsonschema; -import io.quarkus.bootstrap.classloading.QuarkusClassLoader; import io.quarkus.deployment.Feature; import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.annotations.BuildStep; @@ -23,24 +22,14 @@ public void apicurioRegistryJsonSchema(BuildProducer r "io.apicurio.registry.serde.jsonschema.JsonSchemaKafkaSerializer").methods().build()); reflectiveClass.produce(ReflectiveClassBuildItem.builder("io.apicurio.registry.serde.strategy.SimpleTopicIdStrategy", - "io.apicurio.registry.serde.strategy.TopicIdStrategy", - "io.apicurio.registry.serde.strategy.QualifiedRecordIdStrategy", - "io.apicurio.registry.serde.strategy.RecordIdStrategy", - "io.apicurio.registry.serde.jsonschema.strategy.TopicRecordIdStrategy").methods().fields() + "io.apicurio.registry.serde.strategy.TopicIdStrategy").methods().fields() .build()); - reflectiveClass.produce(ReflectiveClassBuildItem.builder("io.apicurio.registry.serde.DefaultIdHandler", - "io.apicurio.registry.serde.Legacy4ByteIdHandler", + reflectiveClass.produce(ReflectiveClassBuildItem.builder("io.apicurio.registry.serde.Default4ByteIdHandler", + "io.apicurio.registry.serde.Legacy8ByteIdHandler", "io.apicurio.registry.serde.fallback.DefaultFallbackArtifactProvider", "io.apicurio.registry.serde.headers.DefaultHeadersHandler").methods().fields() .build()); - - String defaultSchemaResolver = "io.apicurio.registry.serde.DefaultSchemaResolver"; - if (QuarkusClassLoader.isClassPresentAtRuntime(defaultSchemaResolver)) { - // Class not present after 2.2.0.Final - reflectiveClass.produce(ReflectiveClassBuildItem.builder(defaultSchemaResolver).methods() - .fields().build()); - } } @BuildStep diff --git a/extensions/schema-registry/apicurio/json-schema/runtime/pom.xml b/extensions/schema-registry/apicurio/json-schema/runtime/pom.xml index 94c82a3356400..a5a3bc453a127 100644 --- a/extensions/schema-registry/apicurio/json-schema/runtime/pom.xml +++ b/extensions/schema-registry/apicurio/json-schema/runtime/pom.xml @@ -17,13 +17,7 @@ io.apicurio - apicurio-registry-serdes-jsonschema-serde - - - io.apicurio - apicurio-common-rest-client-jdk - - + apicurio-registry-jsonschema-serde-kafka diff --git a/extensions/schema-registry/devservice/deployment/src/main/java/io/quarkus/apicurio/registry/devservice/ApicurioRegistryBuildTimeConfig.java b/extensions/schema-registry/devservice/deployment/src/main/java/io/quarkus/apicurio/registry/devservice/ApicurioRegistryBuildTimeConfig.java index 98507fde7821a..d6532ca739ae7 100644 --- a/extensions/schema-registry/devservice/deployment/src/main/java/io/quarkus/apicurio/registry/devservice/ApicurioRegistryBuildTimeConfig.java +++ b/extensions/schema-registry/devservice/deployment/src/main/java/io/quarkus/apicurio/registry/devservice/ApicurioRegistryBuildTimeConfig.java @@ -40,8 +40,8 @@ interface ApicurioRegistryDevServicesBuildTimeConfig { /** * The Apicurio Registry image to use. - * Note that only Apicurio Registry 2.x images are supported. - * Specifically, the image repository must end with {@code apicurio/apicurio-registry-mem}. + * Note that only Apicurio Registry 3.x images are supported. + * Specifically, the image repository must end with {@code apicurio/apicurio-registry}. */ @ConfigDocDefault(value = "`{apicurio-registry-image}`", escape = false) Optional imageName(); diff --git a/extensions/schema-registry/devservice/deployment/src/main/java/io/quarkus/apicurio/registry/devservice/DevServicesApicurioRegistryProcessor.java b/extensions/schema-registry/devservice/deployment/src/main/java/io/quarkus/apicurio/registry/devservice/DevServicesApicurioRegistryProcessor.java index 2b83d2a270ea5..2261e3e9029e5 100644 --- a/extensions/schema-registry/devservice/deployment/src/main/java/io/quarkus/apicurio/registry/devservice/DevServicesApicurioRegistryProcessor.java +++ b/extensions/schema-registry/devservice/deployment/src/main/java/io/quarkus/apicurio/registry/devservice/DevServicesApicurioRegistryProcessor.java @@ -129,8 +129,8 @@ public void run() { private Map getRegistryUrlConfigs(String baseUrl) { return Map.of( - APICURIO_REGISTRY_URL_CONFIG, baseUrl + "/apis/registry/v2", - CONFLUENT_SCHEMA_REGISTRY_URL_CONFIG, baseUrl + "/apis/ccompat/v6"); + APICURIO_REGISTRY_URL_CONFIG, baseUrl + "/apis/registry/v3", + CONFLUENT_SCHEMA_REGISTRY_URL_CONFIG, baseUrl + "/apis/ccompat/v7"); } private void shutdownApicurioRegistry() { @@ -187,7 +187,7 @@ private RunningDevService startApicurioRegistry(DockerStatusBuildItem dockerStat getRegistryUrlConfigs("http://" + address.getUrl()))) .orElseGet(() -> { ApicurioRegistryContainer container = new ApicurioRegistryContainer( - DockerImageName.parse(config.imageName).asCompatibleSubstituteFor("apicurio/apicurio-registry-mem"), + DockerImageName.parse(config.imageName).asCompatibleSubstituteFor("apicurio/apicurio-registry"), config.fixedExposedPort, launchMode.getLaunchMode() == LaunchMode.DEVELOPMENT ? config.serviceName : null, composeProjectBuildItem.getDefaultNetworkId(), @@ -282,8 +282,8 @@ private ApicurioRegistryContainer(DockerImageName dockerImageName, int fixedExpo withLabel(QUARKUS_DEV_SERVICE, serviceName); } withEnv("QUARKUS_PROFILE", "prod"); - if (!dockerImageName.getRepository().endsWith("apicurio/apicurio-registry-mem")) { - throw new IllegalArgumentException("Only apicurio/apicurio-registry-mem images are supported"); + if (!dockerImageName.getRepository().endsWith("apicurio/apicurio-registry")) { + throw new IllegalArgumentException("Only apicurio/apicurio-registry images are supported"); } this.hostName = ConfigureUtil.configureNetwork(this, defaultNetworkId, useSharedNetwork, "apicurio-registry"); } diff --git a/extensions/smallrye-reactive-messaging-kafka/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/kafka/deployment/DefaultSerdeDiscoveryState.java b/extensions/smallrye-reactive-messaging-kafka/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/kafka/deployment/DefaultSerdeDiscoveryState.java index 1441859a31ce3..2a15336da4dbd 100644 --- a/extensions/smallrye-reactive-messaging-kafka/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/kafka/deployment/DefaultSerdeDiscoveryState.java +++ b/extensions/smallrye-reactive-messaging-kafka/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/kafka/deployment/DefaultSerdeDiscoveryState.java @@ -36,9 +36,9 @@ class DefaultSerdeDiscoveryState { private Boolean connectorHasValueDeserializer; private Boolean hasConfluent; - private Boolean hasApicurio1; - private Boolean hasApicurio2Avro; + private Boolean hasApicurioAvro; private Boolean hasJsonb; + private boolean apicurioVersionWarningLogged; DefaultSerdeDiscoveryState(IndexView index) { this.index = index; @@ -142,32 +142,30 @@ boolean hasConfluent() { return hasConfluent; } - boolean hasApicurio1() { - if (hasApicurio1 == null) { + boolean hasApicurioAvro() { + if (hasApicurioAvro == null) { try { - Class.forName("io.apicurio.registry.utils.serde.AvroKafkaDeserializer", false, + Class.forName("io.apicurio.registry.serde.avro.AvroKafkaDeserializer", false, Thread.currentThread().getContextClassLoader()); - hasApicurio1 = true; + hasApicurioAvro = true; } catch (ClassNotFoundException e) { - hasApicurio1 = false; + hasApicurioAvro = false; } } - return hasApicurio1; + return hasApicurioAvro; } - boolean hasApicurio2Avro() { - if (hasApicurio2Avro == null) { - try { - Class.forName("io.apicurio.registry.serde.avro.AvroKafkaDeserializer", false, - Thread.currentThread().getContextClassLoader()); - hasApicurio2Avro = true; - } catch (ClassNotFoundException e) { - hasApicurio2Avro = false; - } + /** + * Returns true if the Apicurio version warning should be logged (first call only). + * Subsequent calls return false to avoid duplicate warnings. + */ + boolean shouldLogApicurioVersionWarning() { + if (!apicurioVersionWarningLogged && hasApicurioAvro()) { + apicurioVersionWarningLogged = true; + return true; } - - return hasApicurio2Avro; + return false; } boolean hasJsonb() { diff --git a/extensions/smallrye-reactive-messaging-kafka/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/kafka/deployment/SmallRyeReactiveMessagingKafkaProcessor.java b/extensions/smallrye-reactive-messaging-kafka/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/kafka/deployment/SmallRyeReactiveMessagingKafkaProcessor.java index d7a95eeee2456..b0b28d367cdf9 100644 --- a/extensions/smallrye-reactive-messaging-kafka/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/kafka/deployment/SmallRyeReactiveMessagingKafkaProcessor.java +++ b/extensions/smallrye-reactive-messaging-kafka/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/kafka/deployment/SmallRyeReactiveMessagingKafkaProcessor.java @@ -963,8 +963,7 @@ private Result serializerDeserializerFor(DefaultSerdeDiscoveryState discovery, T if (isAvroGenerated || DotNames.AVRO_GENERIC_RECORD.equals(typeName)) { int avroLibraries = 0; avroLibraries += discovery.hasConfluent() ? 1 : 0; - avroLibraries += discovery.hasApicurio1() ? 1 : 0; - avroLibraries += discovery.hasApicurio2Avro() ? 1 : 0; + avroLibraries += discovery.hasApicurioAvro() ? 1 : 0; if (avroLibraries > 1) { LOGGER.debugf("Skipping Avro serde autodetection for %s, because multiple Avro serde libraries are present", typeName); @@ -976,12 +975,13 @@ private Result serializerDeserializerFor(DefaultSerdeDiscoveryState discovery, T ? Result.of("io.confluent.kafka.serializers.KafkaAvroSerializer") : Result.of("io.confluent.kafka.serializers.KafkaAvroDeserializer") .with(isAvroGenerated, "specific.avro.reader", "true"); - } else if (discovery.hasApicurio1()) { - return serializer - ? Result.of("io.apicurio.registry.utils.serde.AvroKafkaSerializer") - : Result.of("io.apicurio.registry.utils.serde.AvroKafkaDeserializer") - .with(isAvroGenerated, "apicurio.registry.use-specific-avro-reader", "true"); - } else if (discovery.hasApicurio2Avro()) { + } else if (discovery.hasApicurioAvro()) { + if (discovery.shouldLogApicurioVersionWarning()) { + LOGGER.info("Apicurio Registry Avro serde detected. Note: Apicurio Registry 3.x uses 4-byte schema IDs " + + "by default, while 2.x used 8-byte IDs. If consuming messages produced by Apicurio Registry 2.x, " + + "configure 'apicurio.registry.id-handler=io.apicurio.registry.serde.Legacy8ByteIdHandler' " + + "on your consumer channels for compatibility."); + } return serializer ? Result.of("io.apicurio.registry.serde.avro.AvroKafkaSerializer") : Result.of("io.apicurio.registry.serde.avro.AvroKafkaDeserializer") diff --git a/integration-tests/kafka-avro-apicurio2/pom.xml b/integration-tests/kafka-avro-apicurio2/pom.xml index 19398b353f8ba..0ddf52194c642 100644 --- a/integration-tests/kafka-avro-apicurio2/pom.xml +++ b/integration-tests/kafka-avro-apicurio2/pom.xml @@ -10,11 +10,16 @@ 4.0.0 quarkus-integration-test-kafka-avro-apicurio2 - Quarkus - Integration Tests - Kafka Avro with Apicurio 2.x - The Apache Kafka Avro with Apicurio Registry 2.x integration tests module + Quarkus - Integration Tests - Kafka Avro with Apicurio Registry + Apache Kafka Avro with Apicurio Registry 3.x integration tests - tests both v2 compatibility mode (Legacy8ByteIdHandler) and v3 native mode (Default4ByteIdHandler) diff --git a/integration-tests/kafka-json-schema-apicurio2/src/main/java/io/quarkus/it/kafka/jsonschema/JsonSchemaKafkaCreator.java b/integration-tests/kafka-json-schema-apicurio2/src/main/java/io/quarkus/it/kafka/jsonschema/JsonSchemaKafkaCreator.java index 119beaf837785..1744bd7a70717 100644 --- a/integration-tests/kafka-json-schema-apicurio2/src/main/java/io/quarkus/it/kafka/jsonschema/JsonSchemaKafkaCreator.java +++ b/integration-tests/kafka-json-schema-apicurio2/src/main/java/io/quarkus/it/kafka/jsonschema/JsonSchemaKafkaCreator.java @@ -14,7 +14,7 @@ import org.apache.kafka.common.serialization.IntegerSerializer; import org.eclipse.microprofile.config.inject.ConfigProperty; -import io.apicurio.registry.serde.SerdeConfig; +import io.apicurio.registry.serde.config.SerdeConfig; import io.apicurio.registry.serde.jsonschema.JsonSchemaKafkaDeserializer; import io.apicurio.registry.serde.jsonschema.JsonSchemaKafkaSerializer; import io.confluent.kafka.serializers.AbstractKafkaSchemaSerDeConfig; diff --git a/integration-tests/kafka-json-schema-apicurio2/src/main/resources/application.properties b/integration-tests/kafka-json-schema-apicurio2/src/main/resources/application.properties index e1de76ce2307d..1ea90c4f24f95 100644 --- a/integration-tests/kafka-json-schema-apicurio2/src/main/resources/application.properties +++ b/integration-tests/kafka-json-schema-apicurio2/src/main/resources/application.properties @@ -8,3 +8,7 @@ quarkus.native.resources.includes=json-schema.json quarkus.kafka.health.enabled=true quarkus.apicurio-registry.devservices.image-name=${apicurio-registry.image} + +# Default configuration uses Legacy8ByteIdHandler for v2 compatibility mode +# This allows Apicurio v3 libraries to work with 8-byte schema IDs (v2 format) +mp.messaging.connector.smallrye-kafka.apicurio.registry.id-handler=io.apicurio.registry.serde.Legacy8ByteIdHandler \ No newline at end of file diff --git a/integration-tests/kafka-json-schema-apicurio2/src/test/java/io/quarkus/it/kafka/KafkaJsonSchemaIT.java b/integration-tests/kafka-json-schema-apicurio2/src/test/java/io/quarkus/it/kafka/KafkaJsonSchemaIT.java index 31ddb23296938..dd04b93ef7136 100644 --- a/integration-tests/kafka-json-schema-apicurio2/src/test/java/io/quarkus/it/kafka/KafkaJsonSchemaIT.java +++ b/integration-tests/kafka-json-schema-apicurio2/src/test/java/io/quarkus/it/kafka/KafkaJsonSchemaIT.java @@ -2,8 +2,7 @@ import org.junit.jupiter.api.BeforeAll; -import io.apicurio.registry.rest.client.RegistryClientFactory; -import io.apicurio.rest.client.VertxHttpClientProvider; +import io.apicurio.registry.resolver.client.RegistryClientFacadeFactory; import io.quarkus.it.kafka.jsonschema.JsonSchemaKafkaCreator; import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.junit.QuarkusIntegrationTest; @@ -23,7 +22,7 @@ JsonSchemaKafkaCreator creator() { @BeforeAll public static void setUp() { // this is for the test JVM, which also uses Kafka client, which in turn also interacts with the registry - RegistryClientFactory.setProvider(new VertxHttpClientProvider(Vertx.vertx())); + RegistryClientFacadeFactory.vertx = Vertx.vertx(); } } diff --git a/integration-tests/kafka-json-schema-apicurio2/src/test/java/io/quarkus/it/kafka/KafkaJsonSchemaTestBase.java b/integration-tests/kafka-json-schema-apicurio2/src/test/java/io/quarkus/it/kafka/KafkaJsonSchemaTestBase.java index 729b8956fd47e..d8217c52190bb 100644 --- a/integration-tests/kafka-json-schema-apicurio2/src/test/java/io/quarkus/it/kafka/KafkaJsonSchemaTestBase.java +++ b/integration-tests/kafka-json-schema-apicurio2/src/test/java/io/quarkus/it/kafka/KafkaJsonSchemaTestBase.java @@ -23,7 +23,7 @@ public abstract class KafkaJsonSchemaTestBase { @Test public void testUrls() { - Assertions.assertTrue(creator().getApicurioRegistryUrl().endsWith("/apis/registry/v2")); + Assertions.assertTrue(creator().getApicurioRegistryUrl().endsWith("/apis/registry/v3")); } @Test