diff --git a/build.gradle b/build.gradle
index 82a0227c70..d90603b3d2 100644
--- a/build.gradle
+++ b/build.gradle
@@ -655,8 +655,8 @@ project("spring-web") {
exclude group: "javax.servlet", module: "javax.servlet-api"
}
optional("log4j:log4j:1.2.17")
- optional("com.googlecode.protobuf-java-format:protobuf-java-format:1.2")
- optional("com.google.protobuf:protobuf-java:${protobufVersion}")
+ optional("com.googlecode.protobuf-java-format:protobuf-java-format:1.2")
+ optional("com.google.protobuf:protobuf-java:${protobufVersion}")
testCompile(project(":spring-context-support")) // for JafMediaTypeFactory
testCompile("xmlunit:xmlunit:1.5")
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
diff --git a/spring-web/src/main/java/org/springframework/http/converter/protobuf/ProtobufHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/protobuf/ProtobufHttpMessageConverter.java
index 3379b13d25..faf2173e82 100644
--- a/spring-web/src/main/java/org/springframework/http/converter/protobuf/ProtobufHttpMessageConverter.java
+++ b/spring-web/src/main/java/org/springframework/http/converter/protobuf/ProtobufHttpMessageConverter.java
@@ -19,8 +19,6 @@ package org.springframework.http.converter.protobuf;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
-import java.io.StringWriter;
-import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.util.concurrent.ConcurrentHashMap;
@@ -39,19 +37,20 @@ import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
-import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
/**
- * Implementation of {@link org.springframework.http.converter.HttpMessageConverter}
- * that can read and write Protobuf {@code Message}s using the
- * Google Protocol buffers library.
+ * An {@code HttpMessageConverter} that can read and write Protobuf
+ * {@link com.google.protobuf.Message} using
+ * Google Protocol buffers.
*
- *
By default, it supports {@code application/json}, {@code application/xml}, {@code text/plain}
- * and {@code application/x-protobuf}. {@code text/html} is only supported when writing messages.
+ *
By default it supports {@code "application/json"}, {@code "application/xml"},
+ * {@code "text/plain"} and {@code "application/x-protobuf"} while writing also
+ * supports {@code "text/html"}
+ *
+ *
To generate Message Java classes you need to install the protoc binary.
*
- *
In order to generate Message Java classes, you should install the protoc binary on your system.
*
Tested against Protobuf version 2.5.0.
*
* @author Alex Antonov
@@ -65,60 +64,63 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter, Method> newBuilderMethodCache =
- new ConcurrentHashMap, Method>();
+ private static final ConcurrentHashMap, Method> methodCache = new ConcurrentHashMap, Method>();
+
private ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
+
/**
- * Construct a new {@code ProtobufHttpMessageConverter}.
+ * Construct a new instance.
*/
public ProtobufHttpMessageConverter() {
this(null);
}
/**
- * Construct a new {@code ProtobufHttpMessageConverter} with a {@link ExtensionRegistryInitializer},
- * allowing to register message extensions.
+ * Construct a new instance with an {@link ExtensionRegistryInitializer}
+ * that allows the registration of message extensions.
*/
public ProtobufHttpMessageConverter(ExtensionRegistryInitializer registryInitializer) {
-
- //TODO: should we handle "*+json", "*+xml" as well?
- super(PROTOBUF, MediaType.TEXT_PLAIN,
- MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON);
- Assert.notNull(registryInitializer, "ExtensionRegistryInitializer must not be null");
- registryInitializer.initializeExtensionRegistry(extensionRegistry);
+ super(PROTOBUF, MediaType.TEXT_PLAIN, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON);
+ if (this.extensionRegistry != null) {
+ registryInitializer.initializeExtensionRegistry(this.extensionRegistry);
+ }
}
+
@Override
protected boolean supports(Class> clazz) {
return Message.class.isAssignableFrom(clazz);
}
-
@Override
- protected Message readInternal(Class extends Message> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
- MediaType contentType = inputMessage.getHeaders().getContentType();
- contentType = contentType != null ? contentType : PROTOBUF;
+ protected Message readInternal(Class extends Message> clazz, HttpInputMessage inputMessage)
+ throws IOException, HttpMessageNotReadableException {
- InputStreamReader reader = new InputStreamReader(inputMessage.getBody(), getCharset(inputMessage.getHeaders()));
+ MediaType contentType = inputMessage.getHeaders().getContentType();
+ contentType = (contentType != null ? contentType : PROTOBUF);
+
+ Charset charset = getCharset(inputMessage.getHeaders());
+ InputStreamReader reader = new InputStreamReader(inputMessage.getBody(), charset);
try {
- Message.Builder builder = createMessageBuilder(clazz);
+ Message.Builder builder = getMessageBuilder(clazz);
if (MediaType.APPLICATION_JSON.isCompatibleWith(contentType)) {
- JsonFormat.merge(reader, extensionRegistry, builder);
+ JsonFormat.merge(reader, this.extensionRegistry, builder);
}
else if (MediaType.TEXT_PLAIN.isCompatibleWith(contentType)) {
- TextFormat.merge(reader, extensionRegistry, builder);
+ TextFormat.merge(reader, this.extensionRegistry, builder);
}
else if (MediaType.APPLICATION_XML.isCompatibleWith(contentType)) {
- XmlFormat.merge(reader, extensionRegistry, builder);
+ XmlFormat.merge(reader, this.extensionRegistry, builder);
}
- else { // ProtobufHttpMessageConverter.PROTOBUF
- builder.mergeFrom(inputMessage.getBody(), extensionRegistry);
+ else {
+ builder.mergeFrom(inputMessage.getBody(), this.extensionRegistry);
}
return builder.build();
}
@@ -138,13 +140,13 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverterThis method uses a ConcurrentHashMap for caching method lookups.
*/
- private Message.Builder createMessageBuilder(Class extends Message> clazz) throws Exception {
- Method m = newBuilderMethodCache.get(clazz);
- if (m == null) {
- m = clazz.getMethod("newBuilder");
- newBuilderMethodCache.put(clazz, m);
+ private Message.Builder getMessageBuilder(Class extends Message> clazz) throws Exception {
+ Method method = methodCache.get(clazz);
+ if (method == null) {
+ method = clazz.getMethod("newBuilder");
+ methodCache.put(clazz, method);
}
- return (Message.Builder) m.invoke(clazz);
+ return (Message.Builder) method.invoke(clazz);
}
/**
@@ -157,7 +159,9 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter