Pulsar: JSON schema support with broker-side registration (#3183)#3210
Merged
Conversation
The Pulsar transport previously sent/received raw bytes only, with no schema
registered on the broker — the single biggest divergence from idiomatic Pulsar.
This adds JSON schema support so a topic gets broker-side schema registration and
Pulsar's schema compatibility / evolution checks, while Wolverine keeps owning the
message body bytes (its normal System.Text.Json serialization).
opts.PublishMessage<OrderPlaced>().ToPulsarTopic(topic).UseJsonSchema<OrderPlaced>();
opts.ListenToPulsarTopic(topic).UseJsonSchema<OrderPlaced>();
- PulsarSchema : ISchema<ReadOnlySequence<byte>> is a pass-through over Wolverine's
bytes whose SchemaInfo declares the schema the broker stores. Because it stays
typed as ReadOnlySequence<byte>, the entire existing sender/listener/mapper and
CloudEvents pipeline is unchanged — the producer/consumer are simply created with
the schema (NewProducer(schema)/NewConsumer(schema)) so the broker registers it.
- AvroSchemaGenerator builds the Avro-format JSON schema Pulsar uses for
SchemaType.Json from a CLR type's public properties (primitives, strings,
enums/Guid/DateTime as strings, nullable value types as ["null", T] unions, arrays,
nested records), falling back to string for anything unmappable so registration
never fails on an exotic property.
- DSL: UseJsonSchema<T>() and UsePulsarSchema(ISchema<...>) on both listener and
subscriber configs. No schema is registered unless opted in, so raw-bytes and
CloudEvents endpoints are unaffected.
AUTO_CONSUME is dropped (not available in DotPulsar 5.1.2). The UsePulsarSchema seam
accepts a custom ISchema for advanced cases (e.g. Avro/Protobuf codecs).
Tests: JSON round-trip with broker-side schema registration verified via the Pulsar
admin REST API; Avro-format schema generator unit tests. Docs: Schema Support section.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced Jun 23, 2026
This was referenced Jun 23, 2026
Closed
This was referenced Jun 26, 2026
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.
Part of the Re-Evaluate Pulsar Integration epic #3176. Addresses #3183 (the headline differentiator) — the JSON-first slice of the revised scope.
The Pulsar transport previously sent/received raw bytes only, with no schema registered on the broker — the single biggest divergence from idiomatic Pulsar. This adds JSON schema support so a topic gets broker-side schema registration and Pulsar's schema compatibility / evolution checks, while Wolverine keeps owning the message body (its normal
System.Text.Jsonserialization).Design — pass-through schema, zero pipeline rewrite
PulsarSchema : ISchema<ReadOnlySequence<byte>>is a pass-through over Wolverine's bytes whoseSchemaInfodeclares the schema the broker stores. Because it stays typed asReadOnlySequence<byte>, the entire existing sender/listener/PulsarEnvelopeMapperand CloudEvents pipeline is unchanged — the producer/consumer are simply created with the schema (NewProducer(schema)/NewConsumer(schema)) so the broker registers it.AvroSchemaGeneratorbuilds the Avro-format JSON schema Pulsar uses forSchemaType.Jsonfrom a CLR type's public properties (primitives, strings, enums/Guid/DateTimeas strings, nullable value types as["null", T]unions, arrays, nested records), falling back tostringfor anything unmappable so registration never fails on an exotic property.UseJsonSchema<T>()andUsePulsarSchema(ISchema<…>)on both listener and subscriber configs.Scope notes
AUTO_CONSUMEis dropped (not available in DotPulsar 5.1.2, per the API verification).UsePulsarSchema(ISchema<ReadOnlySequence<byte>>)seam accepts a custom schema for advanced cases (custom definition /SchemaType/ codec). Built-in typed Avro (Schema.AvroISpecificRecord<T>(), which isISchema<T>and needs the typed producer/consumer path) is a natural follow-up on top of this seam.Acceptance criteria
…/schemas/…/schemaendpoint returningtype: JSON).Tests / build
pulsar_json_schema: JSON round-trip + broker registration (integration) and Avro-format schema generator (unit) — green against a Testcontainers broker.wolverine.slnxbuilds clean in Release.🤖 Generated with Claude Code