Repository navigation
Make the JsonSerializerOptions on Kafka raw-JSON endpoints actually work - #3446
Merged
Merged
Conversation
The options argument on ReceiveRawJson()/PublishRawJson() never had any effect: the mapper branch consuming it on the outgoing side was unreachable (Envelope.Data self-serializes via the endpoint serializer first), the incoming side never consulted it, and the generic ReceiveRawJson<T> overload dropped the argument entirely. Supplying options now sets the endpoint's DefaultSerializer, and JsonOnlyMapper stamps envelope.Serializer/ContentType on incoming records so the endpoint's serializer wins over the global default for content-type-less raw records. Omitting the argument keeps behavior byte-identical. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Final follow-up in the raw-JSON series (#3407, #3442): the
JsonSerializerOptionsargument onReceiveRawJson()andPublishRawJson()has never had any effect on any code path. This makes it real.Why it was dead
Envelope.Datalazily serializes the message through the endpoint's serializer before the mapper runs, soJsonOnlyMapper'sMessage-fallback branch — the only consumer of the stored options — was unreachable. Deleted, along with the now-parameterless options plumbing in the mapper.HandlerPipeline.serializerForfell through to the global default serializer.ReceiveRawJson<T>(options)overload dropped the argument entirely when delegating to theTypeoverload.The fix
Supplying options now sets the endpoint's
DefaultSerializerto aSystemTextJsonSerializerwrapping them — one mechanism that covers both directions coherently ("this endpoint speaks JSON in this dialect"):Envelope.Data→ endpoint serializer → the supplied options.JsonOnlyMappernow stampsenvelope.Serializer(andContentType) from the endpoint, mirroring what the baseEnvelopeMapperdoes — without this, the null content-type on raw records routes deserialization to the global serializer regardless of endpoint configuration. StampingContentTypealso keeps the endpoint's serializer resolvable on a durable-inbox recovery replay, where the transientSerializerreference is lost.Compatibility: gated on
options != null. BareReceiveRawJson<T>()/PublishRawJson()callers see zero change — Wolverine's defaults (camel-cased, case-insensitive reads) still apply, and body bytes are byte-identical to before. Only callers who explicitly passed options see a change, and it's the behavior the parameter has always advertised.Tests
{"color_name": ...}) round-trips throughReceiveRawJson<T>(SnakeCaseLower options)— impossible with the default case-insensitive camelCase serializer, so it proves the options drive deserialization.PublishRawJson(new JsonSerializerOptions())record and asserts a Pascal-cased body — distinct from Wolverine's camel-cased default, proving the options drive serialization.(Test-infra note: both tests use per-run unique topics and
AutoOffsetReset.Earliest; the librdkafkaLatestdefault silently discards records produced while a consumer group is still joining a freshly provisioned topic.)Docs
The Kafka interop upgrade warning gains a bullet stating the options now work and what they control.
🤖 Generated with Claude Code