Polishing in Protobuf encoding support

See gh-37154
This commit is contained in:
rstoyanchev
2026-08-19 10:44:15 +03:00
parent a4720ccf77
commit b0149b842b
3 changed files with 28 additions and 12 deletions
@@ -54,6 +54,7 @@ import org.springframework.util.MimeType;
*
* @author Sebastien Deleuze
* @since 5.1
* @see ProtobufHttpMessageWriter
* @see ProtobufDecoder
*/
public class ProtobufEncoder extends ProtobufCodecSupport implements HttpMessageEncoder<Message> {
@@ -49,6 +49,7 @@ import org.springframework.util.MimeType;
*
* @author Brian Clozel
* @since 6.2
* @see ProtobufHttpMessageWriter
* @see ProtobufJsonDecoder
*/
public class ProtobufJsonEncoder implements HttpMessageEncoder<Message> {
@@ -106,7 +107,10 @@ public class ProtobufJsonEncoder implements HttpMessageEncoder<Message> {
}
@Override
public Flux<DataBuffer> encode(Publisher<? extends Message> inputStream, DataBufferFactory bufferFactory, ResolvableType elementType, @Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
public Flux<DataBuffer> encode(
Publisher<? extends Message> inputStream, DataBufferFactory bufferFactory,
ResolvableType elementType, @Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
if (inputStream instanceof Mono) {
return Mono.from(inputStream)
.map(value -> encodeValue(value, bufferFactory, elementType, mimeType, hints))
@@ -120,17 +124,21 @@ public class ProtobufJsonEncoder implements HttpMessageEncoder<Message> {
.map(value -> {
byte[] prefix = helper.getPrefix();
byte[] delimiter = helper.getDelimiter();
DataBuffer delimiterBuffer = bufferFactory.wrap(delimiter);
DataBuffer dataBuffer = encodeValue(value, bufferFactory, MESSAGE_TYPE, mimeType, hints);
return (prefix.length > 0 ?
bufferFactory.join(List.of(bufferFactory.wrap(prefix), bufferFactory.wrap(delimiter), dataBuffer)) :
bufferFactory.join(List.of(bufferFactory.wrap(delimiter), dataBuffer)));
bufferFactory.join(List.of(bufferFactory.wrap(prefix), delimiterBuffer, dataBuffer)) :
bufferFactory.join(List.of(delimiterBuffer, dataBuffer)));
})
.switchIfEmpty(Mono.fromCallable(() -> bufferFactory.wrap(helper.getPrefix())))
.concatWith(Mono.fromCallable(() -> bufferFactory.wrap(helper.getSuffix())));
}
@Override
public DataBuffer encodeValue(Message message, DataBufferFactory bufferFactory, ResolvableType valueType, @Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
public DataBuffer encodeValue(
Message message, DataBufferFactory bufferFactory, ResolvableType valueType,
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
FastByteArrayOutputStream bos = new FastByteArrayOutputStream();
OutputStreamWriter writer = new OutputStreamWriter(bos, StandardCharsets.UTF_8);
try {
@@ -144,6 +152,7 @@ public class ProtobufJsonEncoder implements HttpMessageEncoder<Message> {
}
}
private static class JsonArrayJoinHelper {
private static final byte[] COMMA_SEPARATOR = {','};
@@ -43,16 +43,22 @@ import static org.springframework.core.ResolvableType.forClass;
*/
class ProtobufJsonEncoderTests extends AbstractEncoderTests<ProtobufJsonEncoder> {
private Msg msg1 =
Msg.newBuilder().setFoo("Foo").setBlah(SecondMsg.newBuilder().setBlah(123).build()).build();
private Msg msg1 = Msg.newBuilder()
.setFoo("Foo")
.setBlah(SecondMsg.newBuilder().setBlah(123).build())
.build();
private Msg msg2 = Msg.newBuilder()
.setFoo("Bar")
.setBlah(SecondMsg.newBuilder().setBlah(456).build())
.build();
private Msg msg2 =
Msg.newBuilder().setFoo("Bar").setBlah(SecondMsg.newBuilder().setBlah(456).build()).build();
public ProtobufJsonEncoderTests() {
super(new ProtobufJsonEncoder(JsonFormat.printer().omittingInsignificantWhitespace()));
}
@Override
@Test
protected void canEncode() throws Exception {
@@ -69,7 +75,7 @@ class ProtobufJsonEncoderTests extends AbstractEncoderTests<ProtobufJsonEncoder>
ResolvableType inputType = forClass(Msg.class);
testEncode(input, inputType, MediaType.APPLICATION_JSON, null, step -> step
.assertNext(dataBuffer -> assertBufferEqualsJson(dataBuffer, "{\"foo\":\"Foo\",\"blah\":{\"blah\":123}}"))
.assertNext(buffer -> assertBufferEqualsJson(buffer, "{\"foo\":\"Foo\",\"blah\":{\"blah\":123}}"))
.verifyComplete());
testEncodeError(input, inputType, MediaType.APPLICATION_JSON, null);
testEncodeCancel(input, inputType, MediaType.APPLICATION_JSON, null);
@@ -91,9 +97,9 @@ class ProtobufJsonEncoderTests extends AbstractEncoderTests<ProtobufJsonEncoder>
ResolvableType inputType = forClass(Msg.class);
testEncode(input, inputType, MediaType.APPLICATION_JSON, null, step -> step
.assertNext(dataBuffer -> assertBufferEqualsJson(dataBuffer, "[{\"foo\":\"Foo\",\"blah\":{\"blah\":123}}"))
.assertNext(dataBuffer -> assertBufferEqualsJson(dataBuffer, ",{\"foo\":\"Bar\",\"blah\":{\"blah\":456}}"))
.assertNext(dataBuffer -> assertBufferEqualsJson(dataBuffer, "]"))
.assertNext(buffer -> assertBufferEqualsJson(buffer, "[{\"foo\":\"Foo\",\"blah\":{\"blah\":123}}"))
.assertNext(buffer -> assertBufferEqualsJson(buffer, ",{\"foo\":\"Bar\",\"blah\":{\"blah\":456}}"))
.assertNext(buffer -> assertBufferEqualsJson(buffer, "]"))
.verifyComplete());
}