Skip to content

BE: Restore SchemaRegistry auto-selection for Avro topics (#1833)#1842

Open
joshuaNathaniel wants to merge 1 commit into
kafbat:mainfrom
joshuaNathaniel:issues/1833
Open

BE: Restore SchemaRegistry auto-selection for Avro topics (#1833)#1842
joshuaNathaniel wants to merge 1 commit into
kafbat:mainfrom
joshuaNathaniel:issues/1833

Conversation

@joshuaNathaniel

@joshuaNathaniel joshuaNathaniel commented May 8, 2026

Copy link
Copy Markdown
Contributor

Fixes #1833

What changes did you make? (Give an overview)

In 1.5.0 the value serde stopped auto-selecting SchemaRegistry for Avro topics and defaulted to String. This brings back the 1.4.2 behavior.

The fix is in three places:

  1. ClusterSerdes.findSerdeByPatternsOrDefault now runs three passes: explicit topicKeysPattern/topicValuesPattern first, then defaultKeySerde/defaultValueSerde, then any serde that says it should be preferred via couldBePreferable and passes canSerialize/canDeserialize. Previously couldBePreferable was wired as a continue inside the pattern loop, so it never actually selected anything (auto-configured SR has a null pattern), and as a side effect it could silently skip explicit user patterns too.

  2. SchemaRegistrySerde.couldBePreferable now matches both TopicNameStrategy and TopicRecordNameStrategy. RecordNameStrategy is left out because subjects there are bare FQNs with no relationship to the topic, so we can't safely guess which topics use them. SR still shows up in the dropdown for those topics (via canSerialize), it's just not the default.

  3. Default for Serde#couldBePreferable flipped from true to false. With pass 3 in place, leaving it at true would have made StringSerde win for everything (it's registered first and canDeserialize is unconditionally true). The opt-in default also matches what SchemaRegistrySerde was already doing as the only override.

Tests:

  • ClusterSerdesTest: there wasn't any coverage on the selection logic, which is why this regression slipped through. Pins the three-pass behavior and the original bug.
  • SchemaRegistrySerdeTest.CouldBePreferableTests: covers each naming strategy plus a few edge cases (opposite target, mixed registry state, subjects belonging to other topics).
  • SerdesInitializerTest: assertion that defaultValueSerde stays null when not configured, so nobody tries to "fix" things by re-adding the old implicit fallback.

Is there anything you'd like reviewers to focus on?

  • The pass ordering in findSerdeByPatternsOrDefault. Want to make sure user config still wins over implicit detection.
  • The choice to keep couldBePreferable narrower than canSerialize. Comment explains it but worth a second pair of eyes.
  • The couldBePreferable interface default flip. It's in serde-api so technically a contract change, but in 1.5.0 the default was effectively unused (the only consumer was the dead continue inside pass 1), so anyone upgrading without overriding the method should see no behavioral difference.

How Has This Been Tested?

  • Manually (please, describe, if necessary)
    • Walked through the subject-strategy-demo for all three strategies across Avro/Protobuf/JSON. Topic-affiliated strategies default to SchemaRegistry; RecordNameStrategy defaults to String.
  • Unit checks
  • Integration checks

Checklist

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation (e.g. ENVIRONMENT VARIABLES)
  • My changes generate no new warnings (e.g. Sonar is happy)
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged

A picture of a cute animal (not mandatory but encouraged)

fennec-fox

Summary by CodeRabbit

  • Bug Fixes

    • Serde selection now follows a clear prioritized order: explicit topic patterns, then cluster defaults, then auto-detection.
    • Schema Registry subject detection improved to avoid sibling-topic collisions and better identify topic-affiliated schemas.
    • Auto-preference tightened: serdes must explicitly opt in to be auto-preferred.
  • Tests

    • Added comprehensive tests covering selection precedence, defaults, key/value targeting, and registry subject preferability.

Review Change Stack

@joshuaNathaniel joshuaNathaniel requested a review from a team as a code owner May 8, 2026 12:46
@kapybro kapybro Bot added status/triage Issues pending maintainers triage area/topics status/triage/manual Manual triage in progress status/triage/completed Automatic triage completed and removed status/triage Issues pending maintainers triage labels May 8, 2026
@coderabbitai

coderabbitai Bot commented May 8, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

ClusterSerdes selection was split into three ordered passes (topic patterns → cluster defaults → auto-detection), Serde.couldBePreferable now defaults to false (opt-in), and SchemaRegistrySerde recognizes default and topic-record-name subjects when deciding preferability.

Changes

Serde Auto-Selection and Preference Detection

Layer / File(s) Summary
ClusterSerdes selection passes
api/src/main/java/io/kafbat/ui/serdes/ClusterSerdes.java
findSerdeByPatternsOrDefault runs three ordered passes: topic-pattern regex matching (no preferability gating), cluster defaultKey/defaultValue fallback, then implicit auto-detection via couldBePreferable; returns Optional.empty() if none match.
SchemaRegistry serde preferability
api/src/main/java/io/kafbat/ui/serdes/builtin/sr/SchemaRegistrySerde.java
couldBePreferable(topic,type) now returns true when registry subjects include the computed default subject (<topic>-key/<topic>-value) or a syntactic topic-record subject <topic>-<record> where the record portion is non-empty and contains no hyphens; adds isTopicRecordSubject.
Serde API contract change
serde-api/src/main/java/io/kafbat/ui/serde/api/Serde.java
Default couldBePreferable(String, Target) implementation changed from true to false and Javadoc updated to require explicit opt-in separate from canSerialize/canDeserialize.
ClusterSerdes selection tests
api/src/test/java/io/kafbat/ui/serdes/ClusterSerdesTest.java
New test suite with StubSerde fixture validating three-pass precedence, registration-order tie-breaking, skipping non-deserializable preferables, and correct key/value targeting behavior.
SchemaRegistry couldBePreferable tests
api/src/test/java/io/kafbat/ui/serdes/builtin/sr/SchemaRegistrySerdeTest.java
CouldBePreferableTests added to validate subject naming strategies and edge cases (mixed strategies, opposite targets, sibling-topic regression, missing subjects).
Serdes initializer integration test
api/src/test/java/io/kafbat/ui/serdes/SerdesInitializerTest.java
New test ensures defaultKeySerde and defaultValueSerde remain null when only built-in serde names/patterns are configured.

Sequence Diagram

sequenceDiagram
  participant Caller
  participant ClusterSerdes
  participant SerdeInstances
  participant ClusterConfig
  Caller->>ClusterSerdes: findSerdeByPatternsOrDefault(topic, target, additionalCheck)
  ClusterSerdes->>SerdeInstances: Pass 1 - topic regex matches (registration order)
  ClusterSerdes->>ClusterConfig: Pass 2 - check configured defaultKeySerde/defaultValueSerde
  ClusterSerdes->>SerdeInstances: Pass 3 - couldBePreferable + additionalCheck
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

scope/backend, type/feature, area/serde

Suggested reviewers

  • germanosin
  • Haarolean

Poem

🐰 Three-choice hop for each topic's thread,
Patterns first, then defaults tread,
Preferable must raise its paw,
Schema subjects filed by law,
Avro now finds its proper bed.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main objective: restoring SchemaRegistry auto-selection for Avro topics, which is the core change addressing issue #1833.
Linked Issues check ✅ Passed The PR addresses the regression in #1833 by implementing three-pass serde selection that restores auto-detection of SchemaRegistry for Avro topics using TopicNameStrategy and TopicRecordNameStrategy, meeting the stated objective.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the regression: serde selection logic, SchemaRegistry preference detection, default behavior changes, and comprehensive tests validating the fix.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@api/src/main/java/io/kafbat/ui/serdes/builtin/sr/SchemaRegistrySerde.java`:
- Around line 406-409: The current prefix match in SchemaRegistrySerde
(schemaSubject / getSchemaSubjects usage) treats subjects like
"orders-dlq-value" as matching "orders" because it only checks startsWith(topic
+ "-"); change the predicate so that a subject only matches the topic prefix if
it is the defaultSubject OR it startsWith(topic + "-") AND does NOT end with
"-key" or "-value" (i.e., exclude subjects suffixed with "-key"/"-value" from
counting as a topic-prefix match for TopicRecordNameStrategy); update the stream
predicate in SchemaRegistrySerde and add a regression test asserting that
"orders" does not match "orders-dlq-value" while still accepting legitimate
topic subjects.

In `@api/src/main/resources/static/openapi/kafbat-ui-api.yaml`:
- Around line 3328-3331: The openAPI schema for the property "maxRetries"
currently allows negative integers; add a floor by adding "minimum: 0" to the
"maxRetries" schema so generated clients and validators reject negative retry
counts (keep the existing "type: integer", "format: int32", and "default: 1").
Locate the "maxRetries" property in the OpenAPI YAML and insert the minimum
constraint directly under its schema block.
- Around line 3316-3317: ApplicationConfig currently exposes sensitive fields in
the response schema; mark the OAuth clientSecret as writeOnly so it is not
serialized in GET /api/config responses by adding writeOnly: true to the
clientSecret property in the OpenAPI schema, and do the same for the sibling
password property (both referenced as clientSecret and password in the
ApplicationConfig schema) to ensure neither is returned to callers while still
allowing them to be provided on input.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3c2c084f-48a2-44ed-94fa-c091dfed304a

📥 Commits

Reviewing files that changed from the base of the PR and between 4bf06dd and b030e07.

📒 Files selected for processing (7)
  • api/src/main/java/io/kafbat/ui/serdes/ClusterSerdes.java
  • api/src/main/java/io/kafbat/ui/serdes/builtin/sr/SchemaRegistrySerde.java
  • api/src/main/resources/static/openapi/kafbat-ui-api.yaml
  • api/src/test/java/io/kafbat/ui/serdes/ClusterSerdesTest.java
  • api/src/test/java/io/kafbat/ui/serdes/SerdesInitializerTest.java
  • api/src/test/java/io/kafbat/ui/serdes/builtin/sr/SchemaRegistrySerdeTest.java
  • serde-api/src/main/java/io/kafbat/ui/serde/api/Serde.java

Comment thread api/src/main/java/io/kafbat/ui/serdes/builtin/sr/SchemaRegistrySerde.java Outdated
Comment thread api/src/main/resources/static/openapi/kafbat-ui-api.yaml Outdated
Comment thread api/src/main/resources/static/openapi/kafbat-ui-api.yaml Outdated
Comment thread api/src/main/resources/static/openapi/kafbat-ui-api.yaml
@IversenMichael

Copy link
Copy Markdown

@joshuaNathaniel Thank you for working on the issue! In version 1.4.2, the SchemaRegistry value serde was automatically selected even for topics using the RecordNameStrategy where the schema must be inferred from the messages themselves and not only from the topic name. Will this also be the case in version 1.5.0 with this fix?

@joshuaNathaniel

Copy link
Copy Markdown
Contributor Author

@joshuaNathaniel Thank you for working on the issue! In version 1.4.2, the SchemaRegistry value serde was automatically selected even for topics using the RecordNameStrategy where the schema must be inferred from the messages themselves and not only from the topic name. Will this also be the case in version 1.5.0 with this fix?

This is a good callout @IversenMichael. Unfortunately, no, it does not. This is why I am looking for feedback on it. I believe the prior behavior was to always default topics using key and value serde to the schema registry for every topic.

I think the intention was to fix the lying dropdown before and we used couldBePreferable to only nominate SR when there were actually linked subjects. But I think there is a bit of a performance concern mixed in here for RecordNameStrategy.

Yeah, I made a comment in that issue and I deleted it. I'm starting to regret that. I think @germanosin has to weigh in on this. We can certainly restore the behavior but how we do it has trade offs.

@joshuaNathaniel

Copy link
Copy Markdown
Contributor Author

Popping back in here. It's been a few days. I just need a wee bit of direction on where we want to go in regards to my last comment. I'm more than happy to do the work and make everyone happy and whole again. :D

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
api/src/test/java/io/kafbat/ui/serdes/ClusterSerdesTest.java (1)

46-49: 💤 Low value

Consider adding a comment to explain the empty method.

The empty configure implementation is intentional for this test stub, but SonarCloud flags it as unclear. A brief comment would document the intent.

📝 Suggested clarification
 `@Override`
 public void configure(PropertyResolver serdeProperties,
                       PropertyResolver kafkaClusterProperties,
                       PropertyResolver globalProperties) {
+  // No configuration needed for test stub
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@api/src/test/java/io/kafbat/ui/serdes/ClusterSerdesTest.java` around lines 46
- 49, The empty configure(PropertyResolver serdeProperties, PropertyResolver
kafkaClusterProperties, PropertyResolver globalProperties) method in
ClusterSerdesTest is intentional but unclear to static analysis; add a concise
inline comment inside the method body explaining that this no-op is deliberate
for the test stub (e.g., “no-op on purpose for test stub”) so reviewers and
SonarCloud understand the intent, referencing the configure method in
ClusterSerdesTest.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@api/src/test/java/io/kafbat/ui/serdes/ClusterSerdesTest.java`:
- Around line 46-49: The empty configure(PropertyResolver serdeProperties,
PropertyResolver kafkaClusterProperties, PropertyResolver globalProperties)
method in ClusterSerdesTest is intentional but unclear to static analysis; add a
concise inline comment inside the method body explaining that this no-op is
deliberate for the test stub (e.g., “no-op on purpose for test stub”) so
reviewers and SonarCloud understand the intent, referencing the configure method
in ClusterSerdesTest.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 59a855bd-2b10-431c-9ec4-d4927783b751

📥 Commits

Reviewing files that changed from the base of the PR and between 9020193 and ca2e62a.

📒 Files selected for processing (6)
  • api/src/main/java/io/kafbat/ui/serdes/ClusterSerdes.java
  • api/src/main/java/io/kafbat/ui/serdes/builtin/sr/SchemaRegistrySerde.java
  • api/src/test/java/io/kafbat/ui/serdes/ClusterSerdesTest.java
  • api/src/test/java/io/kafbat/ui/serdes/SerdesInitializerTest.java
  • api/src/test/java/io/kafbat/ui/serdes/builtin/sr/SchemaRegistrySerdeTest.java
  • serde-api/src/main/java/io/kafbat/ui/serde/api/Serde.java
✅ Files skipped from review due to trivial changes (1)
  • api/src/test/java/io/kafbat/ui/serdes/SerdesInitializerTest.java
🚧 Files skipped from review as they are similar to previous changes (3)
  • api/src/main/java/io/kafbat/ui/serdes/builtin/sr/SchemaRegistrySerde.java
  • api/src/test/java/io/kafbat/ui/serdes/builtin/sr/SchemaRegistrySerdeTest.java
  • api/src/main/java/io/kafbat/ui/serdes/ClusterSerdes.java

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@api/src/test/java/io/kafbat/ui/serdes/ClusterSerdesTest.java`:
- Around line 46-49: The override of configure(...) in StubSerde should include
an explicit no-op note to satisfy static analysis; update the
StubSerde.configure(PropertyResolver serdeProperties, PropertyResolver
kafkaClusterProperties, PropertyResolver globalProperties) method to keep the
empty implementation but add a clear comment stating it is intentionally a no-op
(e.g., "no-op for test stub" or "intentionally left blank") so Sonar/CI
recognizes it as deliberate and not an accidental omission.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d5e2e5f7-e1ab-406f-803a-eafe72c937d6

📥 Commits

Reviewing files that changed from the base of the PR and between ca2e62a and f31321f.

📒 Files selected for processing (6)
  • api/src/main/java/io/kafbat/ui/serdes/ClusterSerdes.java
  • api/src/main/java/io/kafbat/ui/serdes/builtin/sr/SchemaRegistrySerde.java
  • api/src/test/java/io/kafbat/ui/serdes/ClusterSerdesTest.java
  • api/src/test/java/io/kafbat/ui/serdes/SerdesInitializerTest.java
  • api/src/test/java/io/kafbat/ui/serdes/builtin/sr/SchemaRegistrySerdeTest.java
  • serde-api/src/main/java/io/kafbat/ui/serde/api/Serde.java

Comment on lines +46 to +49
public void configure(PropertyResolver serdeProperties,
PropertyResolver kafkaClusterProperties,
PropertyResolver globalProperties) {
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add an explicit no-op note in StubSerde.configure.

Line 46 overrides configure(...) with an empty body; this is valid for a test stub, but it currently triggers Sonar and can fail CI quality gates.

Suggested patch
     `@Override`
     public void configure(PropertyResolver serdeProperties,
                           PropertyResolver kafkaClusterProperties,
                           PropertyResolver globalProperties) {
+      // no-op: test stub intentionally does not require configuration
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public void configure(PropertyResolver serdeProperties,
PropertyResolver kafkaClusterProperties,
PropertyResolver globalProperties) {
}
public void configure(PropertyResolver serdeProperties,
PropertyResolver kafkaClusterProperties,
PropertyResolver globalProperties) {
// no-op: test stub intentionally does not require configuration
}
🧰 Tools
🪛 GitHub Check: SonarCloud Code Analysis

[failure] 46-46: Add a nested comment explaining why this method is empty, throw an UnsupportedOperationException or complete the implementation.

See more on https://sonarcloud.io/project/issues?id=kafbat_kafka-ui&issues=AZ4HoKQI68xee83T1wfo&open=AZ4HoKQI68xee83T1wfo&pullRequest=1842

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@api/src/test/java/io/kafbat/ui/serdes/ClusterSerdesTest.java` around lines 46
- 49, The override of configure(...) in StubSerde should include an explicit
no-op note to satisfy static analysis; update the
StubSerde.configure(PropertyResolver serdeProperties, PropertyResolver
kafkaClusterProperties, PropertyResolver globalProperties) method to keep the
empty implementation but add a clear comment stating it is intentionally a no-op
(e.g., "no-op for test stub" or "intentionally left blank") so Sonar/CI
recognizes it as deliberate and not an accidental omission.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/topics status/triage/completed Automatic triage completed status/triage/manual Manual triage in progress

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Regression: version 1.5.0 does not auto‑select SchemaRegistry value serde for Avro topics

3 participants