Skip to content

Make message decoding in ProtobufDecoder more extensible - #37283

Open
AbhishekLaddha54 wants to merge 1 commit into
spring-projects:mainfrom
AbhishekLaddha54:gh-37265-protobuf-decoder-extensible
Open

AbhishekLaddha54 wants to merge 1 commit into
spring-projects:mainfrom
AbhishekLaddha54:gh-37265-protobuf-decoder-extensible

Conversation

@AbhishekLaddha54

Copy link
Copy Markdown

Fixes gh-37265

Summary

ProtobufDecoder recently gained extensibility for size reading via MessageSizeReader (7.0), but message creation is still hard-coded in a private inner class. This makes gRPC-Web support impossible without copy-paste.

gRPC-Web uses:

  • 5-byte header: 1 byte flag (0x80 = trailer, 0x01 = compressed) + 4 bytes BE length
  • Trailer frames that must be skipped

Changes

  • Add protected ExtensionRegistry getExtensionRegistry()
  • Add protected @Nullable Message decodeMessage(CodedInputStream, ResolvableType) and overload for Class<?> — returning null skips frame
  • Refactor decode(DataBuffer, ...) and MessageDecoderFunction to use decodeMessage()
  • Make MessageDecoderFunction protected with getters and add createMessageDecoderFunction() factory

This mirrors the existing initMessageSizeReader() pattern.

Enables (example)

class GrpcWebDecoder extends ProtobufDecoder {
  @Override protected MessageSizeReader initMessageSizeReader() {
    return new GrpcWebReader(); // reads 5-byte header
  }
  @Override protected Message decodeMessage(CodedInputStream s, ResolvableType t) throws Exception {
    if (isTrailer) return null;
    return super.decodeMessage(s, t);
  }
}

See spring-projects/spring-grpc#427

Testing

./gradlew :spring-web:test --tests "ProtobufDecoderTests" → BUILD SUCCESSFUL, 0 failures

Existing tests unchanged, new hook returns same as old logic by default
text

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Sep 16, 2026
@AbhishekLaddha54
AbhishekLaddha54 force-pushed the gh-37265-protobuf-decoder-extensible branch 2 times, most recently from 2a6cccc to 233ebe9 Compare September 16, 2026 12:26
Previously, the Flux decoding path in ProtobufDecoder hard-coded
message creation via getMessageBuilder().mergeFrom().build() inside
a private inner class, with a private ExtensionRegistry. This made
it impossible to support gRPC-Web framing (5-byte header with trailer
flag 0x80) without copying the entire class.

This commit adds a protected extension point similar to the existing
MessageSizeReader:

- Add protected getExtensionRegistry() accessor
- Add protected decodeMessage(CodedInputStream, ResolvableType) and
  decodeMessage(CodedInputStream, Class) returning @nullable to allow
  skipping trailer frames
- Refactor decode(DataBuffer) and MessageDecoderFunction to delegate
  to decodeMessage()
- Make MessageDecoderFunction protected and add
  createMessageDecoderFunction() factory for full override
- Add getters for elementType and messageSizeReader

This enables spring-grpc to implement gRPC-Web support by overriding
initMessageSizeReader() to parse the 5-byte header and decodeMessage()
to skip trailers, as requested in spring-projects/spring-grpc#427.

Closes spring-projectsgh-37265

Signed-off-by: Abhishek <laddhaabhishek112@gmail.com>
@AbhishekLaddha54
AbhishekLaddha54 force-pushed the gh-37265-protobuf-decoder-extensible branch from 233ebe9 to 3b83c41 Compare September 16, 2026 12:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: waiting-for-triage An issue we've not yet triaged or decided on

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make message decoding in ProtobufDecoder more extensible

2 participants