Browse Source

Allow ProtobufHttpMessageConverter extensions

Make ProtobufFormatDelegate protected and visible to subclasses.
Expose constructor that allows passing the delegate in.

See gh-35403
pull/35684/head
rstoyanchev 2 months ago
parent
commit
754372a1f6
  1. 81
      spring-web/src/main/java/org/springframework/http/converter/protobuf/ProtobufHttpMessageConverter.java
  2. 2
      spring-web/src/main/java/org/springframework/http/converter/protobuf/ProtobufJsonFormatHttpMessageConverter.java
  3. 2
      spring-web/src/test/java/org/springframework/http/converter/protobuf/ProtobufHttpMessageConverterTests.java

81
spring-web/src/main/java/org/springframework/http/converter/protobuf/ProtobufHttpMessageConverter.java

@ -17,9 +17,7 @@ @@ -17,9 +17,7 @@
package org.springframework.http.converter.protobuf;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
@ -105,7 +103,7 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M @@ -105,7 +103,7 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M
final ExtensionRegistry extensionRegistry;
private final @Nullable ProtobufFormatSupport protobufFormatSupport;
private final ProtobufHttpMessageConverter.@Nullable ProtobufFormatDelegate protobufFormatDelegate;
/**
@ -124,21 +122,27 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M @@ -124,21 +122,27 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M
this(null, extensionRegistry);
}
ProtobufHttpMessageConverter(@Nullable ProtobufFormatSupport formatSupport,
/**
* Constructor for a subclass that supports additional formats.
* @param formatDelegate delegate to read and write additional formats
* @param extensionRegistry the registry to populate
*/
protected ProtobufHttpMessageConverter(
ProtobufHttpMessageConverter.@Nullable ProtobufFormatDelegate formatDelegate,
@Nullable ExtensionRegistry extensionRegistry) {
if (formatSupport != null) {
this.protobufFormatSupport = formatSupport;
if (formatDelegate != null) {
this.protobufFormatDelegate = formatDelegate;
}
else if (PROTOBUF_JSON_FORMAT_PRESENT) {
this.protobufFormatSupport = new ProtobufJavaUtilSupport(null, null);
this.protobufFormatDelegate = new ProtobufJavaUtilDelegate(null, null);
}
else {
this.protobufFormatSupport = null;
this.protobufFormatDelegate = null;
}
setSupportedMediaTypes(Arrays.asList(this.protobufFormatSupport != null ?
this.protobufFormatSupport.supportedMediaTypes() : new MediaType[] {PROTOBUF, PLUS_PROTOBUF, TEXT_PLAIN}));
setSupportedMediaTypes(Arrays.asList(this.protobufFormatDelegate != null ?
this.protobufFormatDelegate.supportedMediaTypes() : new MediaType[] {PROTOBUF, PLUS_PROTOBUF, TEXT_PLAIN}));
this.extensionRegistry = (extensionRegistry == null ? ExtensionRegistry.newInstance() : extensionRegistry);
}
@ -172,13 +176,13 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M @@ -172,13 +176,13 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M
PLUS_PROTOBUF.isCompatibleWith(contentType)) {
builder.mergeFrom(inputMessage.getBody(), this.extensionRegistry);
}
else if (TEXT_PLAIN.isCompatibleWith(contentType)) {
else if (MediaType.TEXT_PLAIN.isCompatibleWith(contentType)) {
InputStreamReader reader = new InputStreamReader(inputMessage.getBody(), charset);
TextFormat.merge(reader, this.extensionRegistry, builder);
}
else if (this.protobufFormatSupport != null) {
this.protobufFormatSupport.merge(
inputMessage.getBody(), charset, contentType, this.extensionRegistry, builder);
else if (this.protobufFormatDelegate != null) {
this.protobufFormatDelegate.merge(
inputMessage, contentType, charset, builder, this.extensionRegistry);
}
return builder.build();
}
@ -206,7 +210,7 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M @@ -206,7 +210,7 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M
@Override
protected boolean canWrite(@Nullable MediaType mediaType) {
return (super.canWrite(mediaType) ||
(this.protobufFormatSupport != null && this.protobufFormatSupport.supportsWriteOnly(mediaType)));
(this.protobufFormatDelegate != null && this.protobufFormatDelegate.supportsWriteOnly(mediaType)));
}
@Override
@ -235,8 +239,8 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M @@ -235,8 +239,8 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M
outputStreamWriter.flush();
outputMessage.getBody().flush();
}
else if (this.protobufFormatSupport != null) {
this.protobufFormatSupport.print(message, outputMessage.getBody(), contentType, charset);
else if (this.protobufFormatDelegate != null) {
this.protobufFormatDelegate.print(message, outputMessage, contentType, charset);
outputMessage.getBody().flush();
}
}
@ -259,34 +263,51 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M @@ -259,34 +263,51 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M
/**
* Protobuf format support.
* Contract to enable subclasses to plug in support for additional formats.
*/
interface ProtobufFormatSupport {
protected interface ProtobufFormatDelegate {
/**
* Return the supported media types for the converter.
* <p>Note that {@link #PROTOBUF}, {@link #PLUS_PROTOBUF}, and {@link MediaType#TEXT_PLAIN}
* have built-in support and can be listed in addition to formats
* specific to this delegate.
*/
MediaType[] supportedMediaTypes();
/**
* Whether the media type is supported for writing.
*/
boolean supportsWriteOnly(@Nullable MediaType mediaType);
void merge(InputStream input, Charset charset, MediaType contentType,
ExtensionRegistry extensionRegistry, Message.Builder builder)
/**
* Use merge methods on {@link Message.Builder} to read a message from
* the given {@code HttpInputMessage}.
*/
void merge(HttpInputMessage inputMessage, MediaType contentType, Charset charset,
Message.Builder builder, ExtensionRegistry extensionRegistry)
throws IOException, HttpMessageConversionException;
void print(Message message, OutputStream output, MediaType contentType, Charset charset)
/**
* Use print methods on {@link Message.Builder} to write the message to
* the given {@code HttpOutputMessage}.
*/
void print(Message message, HttpOutputMessage outputMessage, MediaType contentType, Charset charset)
throws IOException, HttpMessageConversionException;
}
/**
* {@link ProtobufFormatSupport} implementation used when
* {@link ProtobufFormatDelegate} implementation used when
* {@code com.google.protobuf.util.JsonFormat} is available.
*/
static class ProtobufJavaUtilSupport implements ProtobufFormatSupport {
static class ProtobufJavaUtilDelegate implements ProtobufFormatDelegate {
private final JsonFormat.Parser parser;
private final JsonFormat.Printer printer;
public ProtobufJavaUtilSupport(JsonFormat.@Nullable Parser parser, JsonFormat.@Nullable Printer printer) {
public ProtobufJavaUtilDelegate(JsonFormat.@Nullable Parser parser, JsonFormat.@Nullable Printer printer) {
this.parser = (parser != null ? parser : JsonFormat.parser());
this.printer = (printer != null ? printer : JsonFormat.printer());
}
@ -302,12 +323,12 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M @@ -302,12 +323,12 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M
}
@Override
public void merge(InputStream input, Charset charset, MediaType contentType,
ExtensionRegistry extensionRegistry, Message.Builder builder)
public void merge(HttpInputMessage inputMessage, MediaType contentType, Charset charset,
Message.Builder builder, ExtensionRegistry extensionRegistry)
throws IOException, HttpMessageConversionException {
if (contentType.isCompatibleWith(APPLICATION_JSON)) {
InputStreamReader reader = new InputStreamReader(input, charset);
InputStreamReader reader = new InputStreamReader(inputMessage.getBody(), charset);
this.parser.merge(reader, builder);
}
else {
@ -317,11 +338,11 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M @@ -317,11 +338,11 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M
}
@Override
public void print(Message message, OutputStream output, MediaType contentType, Charset charset)
public void print(Message message, HttpOutputMessage outputMessage, MediaType contentType, Charset charset)
throws IOException, HttpMessageConversionException {
if (contentType.isCompatibleWith(APPLICATION_JSON)) {
OutputStreamWriter writer = new OutputStreamWriter(output, charset);
OutputStreamWriter writer = new OutputStreamWriter(outputMessage.getBody(), charset);
this.printer.appendTo(message, writer);
writer.flush();
}

2
spring-web/src/main/java/org/springframework/http/converter/protobuf/ProtobufJsonFormatHttpMessageConverter.java

@ -71,7 +71,7 @@ public class ProtobufJsonFormatHttpMessageConverter extends ProtobufHttpMessageC @@ -71,7 +71,7 @@ public class ProtobufJsonFormatHttpMessageConverter extends ProtobufHttpMessageC
public ProtobufJsonFormatHttpMessageConverter(JsonFormat.@Nullable Parser parser,
JsonFormat.@Nullable Printer printer, @Nullable ExtensionRegistry extensionRegistry) {
super(new ProtobufJavaUtilSupport(parser, printer), extensionRegistry);
super(new ProtobufJavaUtilDelegate(parser, printer), extensionRegistry);
}
}

2
spring-web/src/test/java/org/springframework/http/converter/protobuf/ProtobufHttpMessageConverterTests.java

@ -107,7 +107,7 @@ class ProtobufHttpMessageConverterTests { @@ -107,7 +107,7 @@ class ProtobufHttpMessageConverterTests {
@Test
void writeJsonWithGoogleProtobuf() throws IOException {
this.converter = new ProtobufHttpMessageConverter(
new ProtobufHttpMessageConverter.ProtobufJavaUtilSupport(null, null),
new ProtobufHttpMessageConverter.ProtobufJavaUtilDelegate(null, null),
this.extensionRegistry);
MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
MediaType contentType = MediaType.APPLICATION_JSON;

Loading…
Cancel
Save