|
|
|
@ -17,9 +17,7 @@ |
|
|
|
package org.springframework.http.converter.protobuf; |
|
|
|
package org.springframework.http.converter.protobuf; |
|
|
|
|
|
|
|
|
|
|
|
import java.io.IOException; |
|
|
|
import java.io.IOException; |
|
|
|
import java.io.InputStream; |
|
|
|
|
|
|
|
import java.io.InputStreamReader; |
|
|
|
import java.io.InputStreamReader; |
|
|
|
import java.io.OutputStream; |
|
|
|
|
|
|
|
import java.io.OutputStreamWriter; |
|
|
|
import java.io.OutputStreamWriter; |
|
|
|
import java.lang.reflect.Method; |
|
|
|
import java.lang.reflect.Method; |
|
|
|
import java.nio.charset.Charset; |
|
|
|
import java.nio.charset.Charset; |
|
|
|
@ -105,7 +103,7 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M |
|
|
|
|
|
|
|
|
|
|
|
final ExtensionRegistry extensionRegistry; |
|
|
|
final ExtensionRegistry extensionRegistry; |
|
|
|
|
|
|
|
|
|
|
|
private final @Nullable ProtobufFormatSupport protobufFormatSupport; |
|
|
|
private final ProtobufHttpMessageConverter.@Nullable ProtobufFormatDelegate protobufFormatDelegate; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
@ -124,21 +122,27 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M |
|
|
|
this(null, extensionRegistry); |
|
|
|
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) { |
|
|
|
@Nullable ExtensionRegistry extensionRegistry) { |
|
|
|
|
|
|
|
|
|
|
|
if (formatSupport != null) { |
|
|
|
if (formatDelegate != null) { |
|
|
|
this.protobufFormatSupport = formatSupport; |
|
|
|
this.protobufFormatDelegate = formatDelegate; |
|
|
|
} |
|
|
|
} |
|
|
|
else if (PROTOBUF_JSON_FORMAT_PRESENT) { |
|
|
|
else if (PROTOBUF_JSON_FORMAT_PRESENT) { |
|
|
|
this.protobufFormatSupport = new ProtobufJavaUtilSupport(null, null); |
|
|
|
this.protobufFormatDelegate = new ProtobufJavaUtilDelegate(null, null); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else { |
|
|
|
this.protobufFormatSupport = null; |
|
|
|
this.protobufFormatDelegate = null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
setSupportedMediaTypes(Arrays.asList(this.protobufFormatSupport != null ? |
|
|
|
setSupportedMediaTypes(Arrays.asList(this.protobufFormatDelegate != null ? |
|
|
|
this.protobufFormatSupport.supportedMediaTypes() : new MediaType[] {PROTOBUF, PLUS_PROTOBUF, TEXT_PLAIN})); |
|
|
|
this.protobufFormatDelegate.supportedMediaTypes() : new MediaType[] {PROTOBUF, PLUS_PROTOBUF, TEXT_PLAIN})); |
|
|
|
|
|
|
|
|
|
|
|
this.extensionRegistry = (extensionRegistry == null ? ExtensionRegistry.newInstance() : extensionRegistry); |
|
|
|
this.extensionRegistry = (extensionRegistry == null ? ExtensionRegistry.newInstance() : extensionRegistry); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -172,13 +176,13 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M |
|
|
|
PLUS_PROTOBUF.isCompatibleWith(contentType)) { |
|
|
|
PLUS_PROTOBUF.isCompatibleWith(contentType)) { |
|
|
|
builder.mergeFrom(inputMessage.getBody(), this.extensionRegistry); |
|
|
|
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); |
|
|
|
InputStreamReader reader = new InputStreamReader(inputMessage.getBody(), charset); |
|
|
|
TextFormat.merge(reader, this.extensionRegistry, builder); |
|
|
|
TextFormat.merge(reader, this.extensionRegistry, builder); |
|
|
|
} |
|
|
|
} |
|
|
|
else if (this.protobufFormatSupport != null) { |
|
|
|
else if (this.protobufFormatDelegate != null) { |
|
|
|
this.protobufFormatSupport.merge( |
|
|
|
this.protobufFormatDelegate.merge( |
|
|
|
inputMessage.getBody(), charset, contentType, this.extensionRegistry, builder); |
|
|
|
inputMessage, contentType, charset, builder, this.extensionRegistry); |
|
|
|
} |
|
|
|
} |
|
|
|
return builder.build(); |
|
|
|
return builder.build(); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -206,7 +210,7 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
protected boolean canWrite(@Nullable MediaType mediaType) { |
|
|
|
protected boolean canWrite(@Nullable MediaType mediaType) { |
|
|
|
return (super.canWrite(mediaType) || |
|
|
|
return (super.canWrite(mediaType) || |
|
|
|
(this.protobufFormatSupport != null && this.protobufFormatSupport.supportsWriteOnly(mediaType))); |
|
|
|
(this.protobufFormatDelegate != null && this.protobufFormatDelegate.supportsWriteOnly(mediaType))); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
@ -235,8 +239,8 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M |
|
|
|
outputStreamWriter.flush(); |
|
|
|
outputStreamWriter.flush(); |
|
|
|
outputMessage.getBody().flush(); |
|
|
|
outputMessage.getBody().flush(); |
|
|
|
} |
|
|
|
} |
|
|
|
else if (this.protobufFormatSupport != null) { |
|
|
|
else if (this.protobufFormatDelegate != null) { |
|
|
|
this.protobufFormatSupport.print(message, outputMessage.getBody(), contentType, charset); |
|
|
|
this.protobufFormatDelegate.print(message, outputMessage, contentType, charset); |
|
|
|
outputMessage.getBody().flush(); |
|
|
|
outputMessage.getBody().flush(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -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(); |
|
|
|
MediaType[] supportedMediaTypes(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Whether the media type is supported for writing. |
|
|
|
|
|
|
|
*/ |
|
|
|
boolean supportsWriteOnly(@Nullable MediaType mediaType); |
|
|
|
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; |
|
|
|
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; |
|
|
|
throws IOException, HttpMessageConversionException; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* {@link ProtobufFormatSupport} implementation used when |
|
|
|
* {@link ProtobufFormatDelegate} implementation used when |
|
|
|
* {@code com.google.protobuf.util.JsonFormat} is available. |
|
|
|
* {@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.Parser parser; |
|
|
|
|
|
|
|
|
|
|
|
private final JsonFormat.Printer printer; |
|
|
|
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.parser = (parser != null ? parser : JsonFormat.parser()); |
|
|
|
this.printer = (printer != null ? printer : JsonFormat.printer()); |
|
|
|
this.printer = (printer != null ? printer : JsonFormat.printer()); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -302,12 +323,12 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public void merge(InputStream input, Charset charset, MediaType contentType, |
|
|
|
public void merge(HttpInputMessage inputMessage, MediaType contentType, Charset charset, |
|
|
|
ExtensionRegistry extensionRegistry, Message.Builder builder) |
|
|
|
Message.Builder builder, ExtensionRegistry extensionRegistry) |
|
|
|
throws IOException, HttpMessageConversionException { |
|
|
|
throws IOException, HttpMessageConversionException { |
|
|
|
|
|
|
|
|
|
|
|
if (contentType.isCompatibleWith(APPLICATION_JSON)) { |
|
|
|
if (contentType.isCompatibleWith(APPLICATION_JSON)) { |
|
|
|
InputStreamReader reader = new InputStreamReader(input, charset); |
|
|
|
InputStreamReader reader = new InputStreamReader(inputMessage.getBody(), charset); |
|
|
|
this.parser.merge(reader, builder); |
|
|
|
this.parser.merge(reader, builder); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else { |
|
|
|
@ -317,11 +338,11 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@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 { |
|
|
|
throws IOException, HttpMessageConversionException { |
|
|
|
|
|
|
|
|
|
|
|
if (contentType.isCompatibleWith(APPLICATION_JSON)) { |
|
|
|
if (contentType.isCompatibleWith(APPLICATION_JSON)) { |
|
|
|
OutputStreamWriter writer = new OutputStreamWriter(output, charset); |
|
|
|
OutputStreamWriter writer = new OutputStreamWriter(outputMessage.getBody(), charset); |
|
|
|
this.printer.appendTo(message, writer); |
|
|
|
this.printer.appendTo(message, writer); |
|
|
|
writer.flush(); |
|
|
|
writer.flush(); |
|
|
|
} |
|
|
|
} |
|
|
|
|