Repository: netty/netty
Issue: ProtobufDecoder should be upgraded to take advantage of protobuf 2.5 features

From protobuf 2.5 release notes:
"Added Parser to parse directly into messages without a Builder. For
    example,
      Foo foo = Foo.getParser().ParseFrom(input);
    Using Parser is ~25% faster than using Builder to parse messages."

see FastProtobufDecoder:
https://code.google.com/p/protobuf-rpc-pro/issues/detail?id=19#c4


Issue comments:
@kryptonics411 sounds nice.. pull-req welcome :)

yeah,your are right,the  decoder should be update,but I think they are so busy now~:P

It's already fixed thanks to user contrubution.


Pull request review comments:

Patch that resolved the issue:
diff --git a/pom.xml b/pom.xml
index f1ffa4bada2..a669eeda8c1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -84,7 +84,7 @@
     <dependency>
       <groupId>com.google.protobuf</groupId>
       <artifactId>protobuf-java</artifactId>
-      <version>2.4.1</version>
+      <version>2.5.0</version>
       <scope>compile</scope>
       <optional>true</optional>
     </dependency>
diff --git a/src/main/java/org/jboss/netty/handler/codec/protobuf/ProtobufDecoder.java b/src/main/java/org/jboss/netty/handler/codec/protobuf/ProtobufDecoder.java
index 257c33d9041..0f3d619b047 100644
--- a/src/main/java/org/jboss/netty/handler/codec/protobuf/ProtobufDecoder.java
+++ b/src/main/java/org/jboss/netty/handler/codec/protobuf/ProtobufDecoder.java
@@ -66,7 +66,20 @@
  */
 @Sharable
 public class ProtobufDecoder extends OneToOneDecoder {
+    private static final boolean HAS_PARSER;
 
+    static {
+        boolean hasParser = false;
+        try {
+            // MessageLite.getParsetForType() is not available until protobuf 2.5.0.
+            MessageLite.class.getDeclaredMethod("getParserForType");
+            hasParser = true;
+        } catch (Throwable t) {
+            // Ignore
+        }
+
+        HAS_PARSER = hasParser;
+    }
     private final MessageLite prototype;
     private final ExtensionRegistry extensionRegistry;
 
@@ -93,22 +106,30 @@ protected Object decode(
         }
 
         ChannelBuffer buf = (ChannelBuffer) msg;
-        if (buf.hasArray()) {
-            final int offset = buf.readerIndex();
-            if (extensionRegistry == null) {
-                return prototype.newBuilderForType().mergeFrom(
-                        buf.array(), buf.arrayOffset() + offset, buf.readableBytes()).build();
-            } else {
-                return prototype.newBuilderForType().mergeFrom(
-                        buf.array(), buf.arrayOffset() + offset, buf.readableBytes(), extensionRegistry).build();
+        final byte[] array;
+        final int offset;
+        final int length = buf.readableBytes();
+
+        if (buf.hasArray()){
+            array = buf.array();
+            offset = buf.arrayOffset() + buf.readerIndex();
+        }else {
+            array = new byte[length];
+            buf.getBytes(buf.readerIndex(),array,0,length);
+            offset = 0;
+        }
+
+        if (extensionRegistry == null){
+            if(HAS_PARSER){
+                return prototype.getParserForType().parseFrom(array,offset,length);
+            }else{
+                return prototype.newBuilderForType().mergeFrom(array,offset,length).build();
             }
-        } else {
-            if (extensionRegistry == null) {
-                return prototype.newBuilderForType().mergeFrom(
-                        new ChannelBufferInputStream((ChannelBuffer) msg)).build();
-            } else {
-                return prototype.newBuilderForType().mergeFrom(
-                        new ChannelBufferInputStream((ChannelBuffer) msg), extensionRegistry).build();
+        }else {
+            if(HAS_PARSER){
+                return prototype.getParserForType().parseFrom(array,offset,length,extensionRegistry);
+            }else{
+                return prototype.newBuilderForType().mergeFrom(array,offset,length,extensionRegistry).build();
             }
         }
     }


Test patch: