Author: chirino
Date: Wed Oct  8 16:32:15 2008
New Revision: 703019

URL: http://svn.apache.org/viewvc?rev=703019&view=rev
Log:
Added an option to support deferred decoding of messages. 
messages now implement equals() and hashCode()


Added:
    
activemq/sandbox/activemq-protobuf/activemq-protobuf-test/src/main/proto/deferred_decode.proto
    activemq/sandbox/activemq-protobuf/activemq-protobuf-test/src/test/java/org/
    
activemq/sandbox/activemq-protobuf/activemq-protobuf-test/src/test/java/org/apache/
    
activemq/sandbox/activemq-protobuf/activemq-protobuf-test/src/test/java/org/apache/activemq/
    
activemq/sandbox/activemq-protobuf/activemq-protobuf-test/src/test/java/org/apache/activemq/protobuf/
    
activemq/sandbox/activemq-protobuf/activemq-protobuf-test/src/test/java/org/apache/activemq/protobuf/DeferredUnmarshalTest.java
    
activemq/sandbox/activemq-protobuf/activemq-protobuf-test/src/test/java/org/apache/activemq/protobuf/EqualsTest.java
    
activemq/sandbox/activemq-protobuf/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/DeferredDecodeMessage.java
Modified:
    
activemq/sandbox/activemq-protobuf/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/BaseMessage.java
    
activemq/sandbox/activemq-protobuf/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/JavaGenerator.java

Added: 
activemq/sandbox/activemq-protobuf/activemq-protobuf-test/src/main/proto/deferred_decode.proto
URL: 
http://svn.apache.org/viewvc/activemq/sandbox/activemq-protobuf/activemq-protobuf-test/src/main/proto/deferred_decode.proto?rev=703019&view=auto
==============================================================================
--- 
activemq/sandbox/activemq-protobuf/activemq-protobuf-test/src/main/proto/deferred_decode.proto
 (added)
+++ 
activemq/sandbox/activemq-protobuf/activemq-protobuf-test/src/main/proto/deferred_decode.proto
 Wed Oct  8 16:32:15 2008
@@ -0,0 +1,38 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package org.apache.activemq.protobuf;
+option java_outer_classname = "DeferredUnmarshal";
+option deferred_decode = true;
+
+message Foo {
+ 
+  optional int32 field1 =  1;
+  optional int64 field2 =  2;
+ 
+}
+
+
+message Bar {
+ 
+  optional int32 field1 =  1;
+  optional int64 field2 =  2;
+ 
+  optional Foo field3 =  3;
+
+}
+

Added: 
activemq/sandbox/activemq-protobuf/activemq-protobuf-test/src/test/java/org/apache/activemq/protobuf/DeferredUnmarshalTest.java
URL: 
http://svn.apache.org/viewvc/activemq/sandbox/activemq-protobuf/activemq-protobuf-test/src/test/java/org/apache/activemq/protobuf/DeferredUnmarshalTest.java?rev=703019&view=auto
==============================================================================
--- 
activemq/sandbox/activemq-protobuf/activemq-protobuf-test/src/test/java/org/apache/activemq/protobuf/DeferredUnmarshalTest.java
 (added)
+++ 
activemq/sandbox/activemq-protobuf/activemq-protobuf-test/src/test/java/org/apache/activemq/protobuf/DeferredUnmarshalTest.java
 Wed Oct  8 16:32:15 2008
@@ -0,0 +1,75 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.activemq.protobuf;
+
+import org.apache.activemq.protobuf.DeferredUnmarshal.Foo;
+import org.apache.activemq.protobuf.DeferredUnmarshal.Bar;
+
+import com.google.protobuf.InvalidProtocolBufferException;
+
+import junit.framework.TestCase;
+
+public class DeferredUnmarshalTest extends TestCase {
+       
+       public void testDeferredDecoding() throws 
InvalidProtocolBufferException {
+               
+               Foo foo = new Foo();
+               foo.setField1(5);
+               foo.setField2(20);
+               
+               Bar bar = new Bar();
+               
+               // There is no decoding pending so its' considered decoded.
+               assertTrue(bar.isDecoded());
+               
+               bar.setField1(25);
+               bar.setField2(220);
+               bar.setField3(foo);
+               
+               // The message should not be encoded yet.
+               assertFalse(bar.isEncoded());
+
+               // The message should be encoded now..
+               byte[] encodedForm = bar.toUnframedByteArray();
+               assertTrue(bar.isEncoded());
+
+               // Repeated encoding operations should just give back the same 
byte[]
+               assertTrue(encodedForm == bar.toUnframedByteArray());
+
+               // Decoding does not occur until a field is accessed.  The new 
message should still be considered encoded.
+               Bar bar2 = Bar.parseUnframed(encodedForm);
+               assertTrue(bar2.isEncoded());
+               assertFalse(bar2.isDecoded());
+               
+               // This should now decode the message.
+               assertEquals(25, bar2.getField1());
+               assertTrue(bar2.isDecoded());
+               
+               // Since bar2 still has not been modified it should still spit 
out the same byte[]
+               assertTrue(encodedForm == bar2.toUnframedByteArray());
+                               
+               // Nested messages should remain un-decoded.
+               assertFalse( bar2.getField3().isDecoded() );
+               
+               // Changing a field should remove the encoding.
+               bar2.setField1(35);
+               assertFalse(bar2.isEncoded());
+               assertTrue(bar2.isDecoded());
+               
+       }
+
+}

Added: 
activemq/sandbox/activemq-protobuf/activemq-protobuf-test/src/test/java/org/apache/activemq/protobuf/EqualsTest.java
URL: 
http://svn.apache.org/viewvc/activemq/sandbox/activemq-protobuf/activemq-protobuf-test/src/test/java/org/apache/activemq/protobuf/EqualsTest.java?rev=703019&view=auto
==============================================================================
--- 
activemq/sandbox/activemq-protobuf/activemq-protobuf-test/src/test/java/org/apache/activemq/protobuf/EqualsTest.java
 (added)
+++ 
activemq/sandbox/activemq-protobuf/activemq-protobuf-test/src/test/java/org/apache/activemq/protobuf/EqualsTest.java
 Wed Oct  8 16:32:15 2008
@@ -0,0 +1,58 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.activemq.protobuf;
+
+import org.apache.activemq.protobuf.DeferredUnmarshal.Bar;
+import org.apache.activemq.protobuf.DeferredUnmarshal.Foo;
+
+import junit.framework.TestCase;
+
+public class EqualsTest extends TestCase {
+       
+       public void testDeferredUnmarshal() {
+               
+               Bar bar1 = createBar();
+               Bar bar2 = createBar();
+
+               // They should have the same hash and equal the same value.
+               assertTrue(bar1.hashCode()==bar2.hashCode());
+               assertTrue(bar1.equals(bar2));
+               
+               // Change bar2 a little.
+               
+               bar2.setField2(35);
+               
+               assertFalse(bar1.hashCode()==bar2.hashCode());
+               assertFalse(bar1.equals(bar2));
+               
+               
+       }
+
+       private Bar createBar() {
+               Bar bar;
+               Foo foo = new Foo();
+               foo.setField1(5);
+               foo.setField2(20);
+               
+               bar = new Bar();
+               bar.setField1(25);
+               bar.setField2(220);
+               bar.setField3(foo);
+               return bar;
+       }
+
+}

Modified: 
activemq/sandbox/activemq-protobuf/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/BaseMessage.java
URL: 
http://svn.apache.org/viewvc/activemq/sandbox/activemq-protobuf/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/BaseMessage.java?rev=703019&r1=703018&r2=703019&view=diff
==============================================================================
--- 
activemq/sandbox/activemq-protobuf/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/BaseMessage.java
 (original)
+++ 
activemq/sandbox/activemq-protobuf/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/BaseMessage.java
 Wed Oct  8 16:32:15 2008
@@ -39,6 +39,10 @@
     
     abstract public T clone() throws CloneNotSupportedException;
 
+       public void clear() {
+               memoizedSerializedSize = -1;
+       }
+
     ///////////////////////////////////////////////////////////////////
     // Write related helpers.
     ///////////////////////////////////////////////////////////////////
@@ -225,6 +229,7 @@
         return rc;
     }
 
+    abstract protected T checktInitialized() throws 
InvalidProtocolBufferException;
 
     /**
      * Read a raw Varint from the stream.  If larger than 32 bits, discard the
@@ -274,4 +279,8 @@
        }
        return (byte) rc;
     }
+
+       protected void loadAndClear() {
+               memoizedSerializedSize=-1;
+       }
 }

Added: 
activemq/sandbox/activemq-protobuf/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/DeferredDecodeMessage.java
URL: 
http://svn.apache.org/viewvc/activemq/sandbox/activemq-protobuf/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/DeferredDecodeMessage.java?rev=703019&view=auto
==============================================================================
--- 
activemq/sandbox/activemq-protobuf/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/DeferredDecodeMessage.java
 (added)
+++ 
activemq/sandbox/activemq-protobuf/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/DeferredDecodeMessage.java
 Wed Oct  8 16:32:15 2008
@@ -0,0 +1,91 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.activemq.protobuf;
+
+import java.io.IOException;
+
+import com.google.protobuf.CodedInputStream;
+import com.google.protobuf.InvalidProtocolBufferException;
+
+abstract public class DeferredDecodeMessage<T> extends BaseMessage<T>{
+
+       protected byte[] encodedForm;
+       protected boolean decoded=true;
+
+       @Override
+    public T mergeFramed(CodedInputStream input) throws IOException {
+        int length = input.readRawVarint32();
+        int oldLimit = input.pushLimit(length);
+        T rc=  mergeUnframed(input.readRawBytes(length));
+        input.popLimit(oldLimit);
+        return rc;
+    }
+
+       @SuppressWarnings("unchecked")
+       @Override
+       public T mergeUnframed(byte[] data) throws 
InvalidProtocolBufferException {
+               encodedForm = data;
+               decoded=false;
+               return (T)this;
+       }
+
+       @Override
+       public byte[] toUnframedByteArray() {
+               if( encodedForm==null ) {
+                       encodedForm = super.toUnframedByteArray();
+               }
+               return encodedForm;
+       }
+
+       protected void load() {
+               if (!decoded) {
+                       decoded = true;
+                       try {
+                               byte[] originalForm = encodedForm;
+                               CodedInputStream input = 
CodedInputStream.newInstance(originalForm);
+                               mergeUnframed(input);
+                               input.checkLastTagWas(0);
+                               // We need to reset the encoded form because 
the mergeUnframed from a stream clears it out.
+                               encodedForm = originalForm;
+                               checktInitialized();
+                       } catch (Throwable e) {
+                               throw new RuntimeException("Deferred message 
decoding failed: "+e.getMessage(), e);
+                       }
+               }
+       }
+       
+       protected void loadAndClear() {
+               super.loadAndClear();
+               load();
+               encodedForm = null;
+       }
+
+       public void clear() {
+               super.clear();
+               encodedForm = null;
+               decoded = true;
+       }
+
+       public boolean isDecoded() {
+               return decoded;
+       }
+       
+       public boolean isEncoded() {
+               return encodedForm!=null;
+       }
+
+}

Modified: 
activemq/sandbox/activemq-protobuf/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/JavaGenerator.java
URL: 
http://svn.apache.org/viewvc/activemq/sandbox/activemq-protobuf/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/JavaGenerator.java?rev=703019&r1=703018&r2=703019&view=diff
==============================================================================
--- 
activemq/sandbox/activemq-protobuf/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/JavaGenerator.java
 (original)
+++ 
activemq/sandbox/activemq-protobuf/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/JavaGenerator.java
 Wed Oct  8 16:32:15 2008
@@ -29,6 +29,7 @@
 import java.io.FileOutputStream;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -48,10 +49,9 @@
     private String outerClassName;
     private PrintWriter w;
     private int indent;
-    private String optimizeFor;
     private ArrayList<String> errors = new ArrayList<String>();
     private boolean multipleFiles;
-       private boolean defferedUnmarshall;
+       private boolean deferredDecode;
 
     public static void main(String[] args) {
         
@@ -121,9 +121,9 @@
         // Load the options..
         javaPackage = javaPackage(proto);
         outerClassName = javaClassName(proto);
-        optimizeFor = getOption(proto.getOptions(), "optimize_for", "SPEED");
+//        optimizeFor = getOption(proto.getOptions(), "optimize_for", "SPEED");
         multipleFiles = isMultipleFilesEnabled(proto);
-        defferedUnmarshall = Boolean.getBoolean(getOption(proto.getOptions(), 
"deferred_unmarshall", "false"));
+               deferredDecode = 
Boolean.parseBoolean(getOption(proto.getOptions(), "deferred_decode", "false"));
         
         if( multipleFiles ) {
             generateProtoFile();
@@ -267,7 +267,13 @@
             implementsExpression = "implements "+javaImplements+" ";
         }
         
-        p("public "+staticOption+"final class " + className + " extends 
org.apache.activemq.protobuf.BaseMessage<" + className + "> 
"+implementsExpression+"{");
+        String baseClass = "org.apache.activemq.protobuf.BaseMessage";
+        if( deferredDecode ) {
+            baseClass = "org.apache.activemq.protobuf.DeferredDecodeMessage";
+        }
+        
+        
+        p("public "+staticOption+"final class " + className + " extends 
"+baseClass+"<" + className + "> "+implementsExpression+"{");
         p();
 
         indent();
@@ -320,13 +326,15 @@
         generateMethodVisitor(m);
                 
         generateMethodType(m, className);
+        
+        generateMethodEquals(m, className);
                 
         unindent();
         p("}");
         p();
     }
 
-    /**
+       /**
      * If the java_visitor message option is set, then this method generates a 
visitor method.  The option 
      * speifiies the class name of the visitor and optionally the return value 
and exceptions thrown by the visitor.
      * 
@@ -411,69 +419,184 @@
     }
     
     private void generateMethodParseFrom(MessageDescriptor m, String 
className) {
+       
+       String postMergeProcessing = ".checktInitialized()";
+        if( deferredDecode ) {
+               postMergeProcessing="";
+        }
+        
         p("public static "+className+" 
parseUnframed(com.google.protobuf.CodedInputStream data) throws 
com.google.protobuf.InvalidProtocolBufferException, java.io.IOException {");
         indent();
-        p("return new 
"+className+"().mergeUnframed(data).checktInitialized();");
+        p("return new 
"+className+"().mergeUnframed(data)"+postMergeProcessing+";");
         unindent();
         p("}");
         p();
 
         p("public static "+className+" 
parseUnframed(com.google.protobuf.ByteString data) throws 
com.google.protobuf.InvalidProtocolBufferException {");
         indent();
-        p("return new 
"+className+"().mergeUnframed(data).checktInitialized();");
+        p("return new 
"+className+"().mergeUnframed(data)"+postMergeProcessing+";");
         unindent();
         p("}");
         p();
 
         p("public static "+className+" parseUnframed(byte[] data) throws 
com.google.protobuf.InvalidProtocolBufferException {");
         indent();
-        p("return new 
"+className+"().mergeUnframed(data).checktInitialized();");
+        p("return new 
"+className+"().mergeUnframed(data)"+postMergeProcessing+";");
         unindent();
         p("}");
         p();
         
         p("public static "+className+" parseUnframed(java.io.InputStream data) 
throws com.google.protobuf.InvalidProtocolBufferException, java.io.IOException 
{");
         indent();
-        p("return new 
"+className+"().mergeUnframed(data).checktInitialized();");
+        p("return new 
"+className+"().mergeUnframed(data)"+postMergeProcessing+";");
         unindent();
         p("}");
         p();
         
         p("public static "+className+" 
parseFramed(com.google.protobuf.CodedInputStream data) throws 
com.google.protobuf.InvalidProtocolBufferException, java.io.IOException {");
         indent();
-        p("return new "+className+"().mergeFramed(data).checktInitialized();");
+        p("return new 
"+className+"().mergeFramed(data)"+postMergeProcessing+";");
         unindent();
         p("}");
         p();
         
         p("public static "+className+" 
parseFramed(com.google.protobuf.ByteString data) throws 
com.google.protobuf.InvalidProtocolBufferException {");
         indent();
-        p("return new "+className+"().mergeFramed(data).checktInitialized();");
+        p("return new 
"+className+"().mergeFramed(data)"+postMergeProcessing+";");
         unindent();
         p("}");
         p();
 
         p("public static "+className+" parseFramed(byte[] data) throws 
com.google.protobuf.InvalidProtocolBufferException {");
         indent();
-        p("return new "+className+"().mergeFramed(data).checktInitialized();");
+        p("return new 
"+className+"().mergeFramed(data)"+postMergeProcessing+";");
         unindent();
         p("}");
         p();
         
         p("public static "+className+" parseFramed(java.io.InputStream data) 
throws com.google.protobuf.InvalidProtocolBufferException, java.io.IOException 
{");
         indent();
-        p("return new "+className+"().mergeFramed(data).checktInitialized();");
+        p("return new 
"+className+"().mergeFramed(data)"+postMergeProcessing+";");
         unindent();
         p("}");
         p();
     }
 
+    private void generateMethodEquals(MessageDescriptor m, String className) {
+        p("public boolean equals(Object obj) {");
+        indent();
+        p("if( obj==this )");
+        p("   return true;");
+        p("");
+        p("if( obj==null || obj.getClass()!="+className+".class )");
+        p("   return false;");
+        p("");
+        p("return equals(("+className+")obj);");
+        unindent();
+        p("}");
+        p("");
+        
+        p("public boolean equals("+className+" obj) {");
+        indent();
+        if( deferredDecode ) {
+               p("return java.util.Arrays.equals(toUnframedByteArray(), 
obj.toUnframedByteArray());");
+        } else {        
+               for (FieldDescriptor field : m.getFields().values()) {
+                   String uname = uCamel(field.getName());
+                   String getterMethod="get"+uname+"()";     
+                   String hasMethod = "has"+uname+"()";
+       
+                   if( field.getRule() == FieldDescriptor.REPEATED_RULE ) {
+                       getterMethod = "get"+uname+"List()";
+                   }
+                   
+                   p("if ("+hasMethod+" ^ obj."+hasMethod+" ) ");
+                   p("   return false;");
+                   
+                   
+                   
+                   if( field.getRule() != FieldDescriptor.REPEATED_RULE && 
(field.isNumberType() || field.getType()==FieldDescriptor.BOOL_TYPE) ) {
+                       p("if ("+hasMethod+" && ( 
"+getterMethod+"!=obj."+getterMethod+" ))");
+                   } else {
+                       p("if ("+hasMethod+" && ( 
!"+getterMethod+".equals(obj."+getterMethod+") ))");
+                   }
+                   p("   return false;");
+               }
+               p("return true;");
+        }
+        unindent();
+        p("}");
+        p("");
+        p("public int hashCode() {");
+        indent();
+        if( deferredDecode ) {
+               int hc = className.hashCode();
+               p("byte []target = new byte[]{ (byte)"+((hc>>24)&0xFF)+", 
(byte)"+((hc>>16)&0xFF)+", (byte)"+((hc>>8)&0xFF)+", (byte)"+(hc&0xFF)+" };");
+               p("byte []data = toUnframedByteArray();");
+               p("for(int i=0; i < data.length; i++) {");
+            indent();
+               p("target[i%4] ^= data[i];");
+            unindent();
+               p("}");
+               p("");
+            p("return target[0]<<24 | target[1]<<16 | target[2]<<8 | 
target[3];");
+        } else {
+            p("int rc="+className.hashCode()+";");
+               int counter=0;
+               for (FieldDescriptor field : m.getFields().values()) {
+                       counter++;
+                       
+                   String uname = uCamel(field.getName());
+                   String getterMethod="get"+uname+"()";     
+                   String hasMethod = "has"+uname+"()";
+       
+                   if( field.getRule() == FieldDescriptor.REPEATED_RULE ) {
+                       getterMethod = "get"+uname+"List()";
+                   }
+                   
+                   p("if ("+hasMethod+") {");
+                   indent();
+                   
+                   if( field.getRule() == FieldDescriptor.REPEATED_RULE ) {
+                       p("rc ^= ( 
"+uname.hashCode()+"^"+getterMethod+".hashCode() );");
+                   } else if( field.isInteger32Type() ) {
+                       p("rc ^= ( "+uname.hashCode()+"^"+getterMethod+" );");
+                   } else if( field.isInteger64Type() ) {
+                       p("rc ^= ( "+uname.hashCode()+"^(new 
Long("+getterMethod+")).hashCode() );");
+                   } else if( field.getType()==FieldDescriptor.DOUBLE_TYPE ) {
+                       p("rc ^= ( "+uname.hashCode()+"^(new 
Double("+getterMethod+")).hashCode() );");
+                   } else if( field.getType()==FieldDescriptor.FLOAT_TYPE ) {
+                       p("rc ^= ( "+uname.hashCode()+"^(new 
Double("+getterMethod+")).hashCode() );");
+                   } else if( field.getType()==FieldDescriptor.BOOL_TYPE ) {
+                       p("rc ^= ( "+uname.hashCode()+"^ ("+getterMethod+"? 
"+counter+":-"+counter+") );");
+                   } else {
+                       p("rc ^= ( 
"+uname.hashCode()+"^"+getterMethod+".hashCode() );");
+                   }
+                   
+                   unindent();
+                   p("}");
+                   
+               }
+               p("return rc;");
+        }
+        unindent();
+        p("}");
+        p("");
+       }
+    
     /**
      * @param m
      */
     private void generateMethodSerializedSize(MessageDescriptor m) {
         p("public int serializedSizeUnframed() {");
         indent();
+        if( deferredDecode ) {
+                       p("if (encodedForm != null) {");
+                       indent();
+            p("return encodedForm.length;");
+                       unindent();
+                       p("}");
+        }
         p("if (memoizedSerializedSize != -1)");
         p("   return memoizedSerializedSize;");
         p();
@@ -553,6 +676,16 @@
     private void generateMethodWriteTo(MessageDescriptor m) {
         p("public void writeUnframed(com.google.protobuf.CodedOutputStream 
output) throws java.io.IOException {");
         indent();
+        
+        if( deferredDecode ) {
+                       p("if (encodedForm == null) {");
+                       indent();
+                       p("encodedForm = new byte[serializedSizeUnframed()];");
+                       p("com.google.protobuf.CodedOutputStream original = 
output;");
+                       p("output = 
com.google.protobuf.CodedOutputStream.newInstance(encodedForm);");
+        }
+        
+
         for (FieldDescriptor field : m.getFields().values()) {
             String uname = uCamel(field.getName());
             String getter="get"+uname+"()";            
@@ -613,8 +746,15 @@
             unindent();
             p("}");
         }
-        // TODO: handle unknown fields
-        // getUnknownFields().writeTo(output);
+        
+        if( deferredDecode ) {
+               p("output.checkNoSpaceLeft();");
+                       p("output = original;");
+                       unindent();
+                       p("}");
+               p("output.writeRawBytes(encodedForm);");
+        }        
+
         unindent();
         p("}");
         p();        
@@ -626,158 +766,188 @@
      */
     private void generateMethodMergeFromStream(MessageDescriptor m, String 
className) {
         p("public "+className+" 
mergeUnframed(com.google.protobuf.CodedInputStream input) throws 
java.io.IOException {");
-        indent(); {
-          p("while (true) {");
-          indent(); {
-              p("int tag = input.readTag();");
-              p("if ((tag & 0x07) == 4) {");
-              p("   return this;");
-              p("}");
-              
-              p("switch (tag) {");
-              p("case 0:");
-              p("   return this;");
-              p("default: {");
-
-              p("   break;");
-              p("}");
-              
-              
-              for (FieldDescriptor field : m.getFields().values()) {
-                  String uname = uCamel(field.getName());
-                  String setter = "set"+uname;
-                  boolean repeated = field.getRule() == 
FieldDescriptor.REPEATED_RULE;
-                  if( repeated ) {
-                      setter = "get"+uname+"List().add";
-                  }
-                  if( field.getType()==FieldDescriptor.STRING_TYPE ) {
-                      p("case "+makeTag(field.getTag(), 
WIRETYPE_LENGTH_DELIMITED)+":");
-                      indent();
-                      p(setter+"(input.readString());");
-                  } else if( field.getType()==FieldDescriptor.BYTES_TYPE ) {
-                      p("case "+makeTag(field.getTag(), 
WIRETYPE_LENGTH_DELIMITED)+":");
-                      indent();
-                      p(setter+"(input.readBytes());");
-                  } else if( field.getType()==FieldDescriptor.BOOL_TYPE ) {
-                      p("case "+makeTag(field.getTag(), WIRETYPE_VARINT)+":");
-                      indent();
-                      p(setter+"(input.readBool());");
-                  } else if( field.getType()==FieldDescriptor.DOUBLE_TYPE ) {
-                      p("case "+makeTag(field.getTag(), WIRETYPE_FIXED64)+":");
-                      indent();
-                      p(setter+"(input.readDouble());");
-                  } else if( field.getType()==FieldDescriptor.FLOAT_TYPE ) {
-                      p("case "+makeTag(field.getTag(), WIRETYPE_FIXED32)+":");
-                      indent();
-                      p(setter+"(input.readFloat());");
-                  } else if( field.getType()==FieldDescriptor.INT32_TYPE ) {
-                      p("case "+makeTag(field.getTag(), WIRETYPE_VARINT)+":");
-                      indent();
-                      p(setter+"(input.readInt32());");
-                  } else if( field.getType()==FieldDescriptor.INT64_TYPE ) {
-                      p("case "+makeTag(field.getTag(), WIRETYPE_VARINT)+":");
-                      indent();
-                      p(setter+"(input.readInt64());");
-                  } else if( field.getType()==FieldDescriptor.SINT32_TYPE ) {
-                      p("case "+makeTag(field.getTag(), WIRETYPE_VARINT)+":");
-                      indent();
-                      p(setter+"(input.readSInt32());");
-                  } else if( field.getType()==FieldDescriptor.SINT64_TYPE ) {
-                      p("case "+makeTag(field.getTag(), WIRETYPE_VARINT)+":");
-                      indent();
-                      p(setter+"(input.readSInt64());");
-                  } else if( field.getType()==FieldDescriptor.UINT32_TYPE ) {
-                      p("case "+makeTag(field.getTag(), WIRETYPE_VARINT)+":");
-                      indent();
-                      p(setter+"(input.readUInt32());");
-                  } else if( field.getType()==FieldDescriptor.UINT64_TYPE ) {
-                      p("case "+makeTag(field.getTag(), WIRETYPE_VARINT)+":");
-                      indent();
-                      p(setter+"(input.readUInt64());");
-                  } else if( field.getType()==FieldDescriptor.FIXED32_TYPE ) {
-                      p("case "+makeTag(field.getTag(), WIRETYPE_FIXED32)+":");
-                      indent();
-                      p(setter+"(input.readFixed32());");
-                  } else if( field.getType()==FieldDescriptor.FIXED64_TYPE ) {
-                      p("case "+makeTag(field.getTag(), WIRETYPE_FIXED64)+":");
-                      indent();
-                      p(setter+"(input.readFixed64());");
-                  } else if( field.getType()==FieldDescriptor.SFIXED32_TYPE ) {
-                      p("case "+makeTag(field.getTag(), WIRETYPE_FIXED32)+":");
-                      indent();
-                      p(setter+"(input.readSFixed32());");
-                  } else if( field.getType()==FieldDescriptor.SFIXED64_TYPE ) {
-                      p("case "+makeTag(field.getTag(), WIRETYPE_FIXED64)+":");
-                      indent();
-                      p(setter+"(input.readSFixed64());");
-                  } else if( field.getTypeDescriptor().isEnum() ) {
-                      p("case "+makeTag(field.getTag(), WIRETYPE_VARINT)+":");
-                      indent();
-                      String type = javaType(field);
-                      p("{");
-                      indent();
-                      p("int t = input.readEnum();");
-                      p(""+type+" value = "+type+".valueOf(t);");
-                      p("if( value !=null ) {");
-                      indent();
-                      p(setter+"(value);");
-                      unindent();
-                      p("}");
-                      // TODO: else store it as an known
-                      
-                      unindent();
-                      p("}");
-                      
-                  } else if ( field.getGroup()!=null ) {
-                      p("case "+makeTag(field.getTag(), 
WIRETYPE_START_GROUP)+":");
-                      indent();
-                      String type = javaType(field);
-                      if( repeated ) {
-                          p(setter+"(readGroup(input, "+field.getTag()+", new 
"+type+"()));");
-                      } else {
-                          p("if (has"+uname+"()) {");
-                          indent();
-                          p("readGroup(input, "+field.getTag()+", 
get"+uname+"());");
-                          unindent();
-                          p("} else {");
-                          indent();
-                          p(setter+"(readGroup(input, "+field.getTag()+",new 
"+type+"()));");
-                          unindent();
-                          p("}");
-                      }
-                      p("");
-                  } else {
-                      p("case "+makeTag(field.getTag(), 
WIRETYPE_LENGTH_DELIMITED)+":");
-                      indent();
-                      String type = javaType(field);
-                      if( repeated ) {
-                          p(setter+"(new "+type+"().mergeFramed(input));");
-                      } else {
-                          p("if (has"+uname+"()) {");
-                          indent();
-                          p("get"+uname+"().mergeFramed(input);");
-                          unindent();
-                          p("} else {");
-                          indent();
-                          p(setter+"(new "+type+"().mergeFramed(input));");
-                          unindent();
-                          p("}");
-                      }
-                  }
-                  p("break;");
-                  unindent();
-              }              
-              p("}");
-          } unindent();
-          p("}"); 
-        } unindent();
-        p("}");
+        indent();
+               {        
+                       p("while (true) {");
+                       indent();
+                       {
+                               p("int tag = input.readTag();");
+                               p("if ((tag & 0x07) == 4) {");
+                               p("   return this;");
+                               p("}");
+
+                               p("switch (tag) {");
+                               p("case 0:");
+                               p("   return this;");
+                               p("default: {");
+
+                               p("   break;");
+                               p("}");
+
+                               for (FieldDescriptor field : 
m.getFields().values()) {
+                                       String uname = uCamel(field.getName());
+                                       String setter = "set" + uname;
+                                       boolean repeated = field.getRule() == 
FieldDescriptor.REPEATED_RULE;
+                                       if (repeated) {
+                                               setter = "get" + uname + 
"List().add";
+                                       }
+                                       if (field.getType() == 
FieldDescriptor.STRING_TYPE) {
+                                               p("case "
+                                                               + 
makeTag(field.getTag(),
+                                                                               
WIRETYPE_LENGTH_DELIMITED) + ":");
+                                               indent();
+                                               p(setter + 
"(input.readString());");
+                                       } else if (field.getType() == 
FieldDescriptor.BYTES_TYPE) {
+                                               p("case "
+                                                               + 
makeTag(field.getTag(),
+                                                                               
WIRETYPE_LENGTH_DELIMITED) + ":");
+                                               indent();
+                                               p(setter + 
"(input.readBytes());");
+                                       } else if (field.getType() == 
FieldDescriptor.BOOL_TYPE) {
+                                               p("case " + 
makeTag(field.getTag(), WIRETYPE_VARINT)
+                                                               + ":");
+                                               indent();
+                                               p(setter + 
"(input.readBool());");
+                                       } else if (field.getType() == 
FieldDescriptor.DOUBLE_TYPE) {
+                                               p("case " + 
makeTag(field.getTag(), WIRETYPE_FIXED64)
+                                                               + ":");
+                                               indent();
+                                               p(setter + 
"(input.readDouble());");
+                                       } else if (field.getType() == 
FieldDescriptor.FLOAT_TYPE) {
+                                               p("case " + 
makeTag(field.getTag(), WIRETYPE_FIXED32)
+                                                               + ":");
+                                               indent();
+                                               p(setter + 
"(input.readFloat());");
+                                       } else if (field.getType() == 
FieldDescriptor.INT32_TYPE) {
+                                               p("case " + 
makeTag(field.getTag(), WIRETYPE_VARINT)
+                                                               + ":");
+                                               indent();
+                                               p(setter + 
"(input.readInt32());");
+                                       } else if (field.getType() == 
FieldDescriptor.INT64_TYPE) {
+                                               p("case " + 
makeTag(field.getTag(), WIRETYPE_VARINT)
+                                                               + ":");
+                                               indent();
+                                               p(setter + 
"(input.readInt64());");
+                                       } else if (field.getType() == 
FieldDescriptor.SINT32_TYPE) {
+                                               p("case " + 
makeTag(field.getTag(), WIRETYPE_VARINT)
+                                                               + ":");
+                                               indent();
+                                               p(setter + 
"(input.readSInt32());");
+                                       } else if (field.getType() == 
FieldDescriptor.SINT64_TYPE) {
+                                               p("case " + 
makeTag(field.getTag(), WIRETYPE_VARINT)
+                                                               + ":");
+                                               indent();
+                                               p(setter + 
"(input.readSInt64());");
+                                       } else if (field.getType() == 
FieldDescriptor.UINT32_TYPE) {
+                                               p("case " + 
makeTag(field.getTag(), WIRETYPE_VARINT)
+                                                               + ":");
+                                               indent();
+                                               p(setter + 
"(input.readUInt32());");
+                                       } else if (field.getType() == 
FieldDescriptor.UINT64_TYPE) {
+                                               p("case " + 
makeTag(field.getTag(), WIRETYPE_VARINT)
+                                                               + ":");
+                                               indent();
+                                               p(setter + 
"(input.readUInt64());");
+                                       } else if (field.getType() == 
FieldDescriptor.FIXED32_TYPE) {
+                                               p("case " + 
makeTag(field.getTag(), WIRETYPE_FIXED32)
+                                                               + ":");
+                                               indent();
+                                               p(setter + 
"(input.readFixed32());");
+                                       } else if (field.getType() == 
FieldDescriptor.FIXED64_TYPE) {
+                                               p("case " + 
makeTag(field.getTag(), WIRETYPE_FIXED64)
+                                                               + ":");
+                                               indent();
+                                               p(setter + 
"(input.readFixed64());");
+                                       } else if (field.getType() == 
FieldDescriptor.SFIXED32_TYPE) {
+                                               p("case " + 
makeTag(field.getTag(), WIRETYPE_FIXED32)
+                                                               + ":");
+                                               indent();
+                                               p(setter + 
"(input.readSFixed32());");
+                                       } else if (field.getType() == 
FieldDescriptor.SFIXED64_TYPE) {
+                                               p("case " + 
makeTag(field.getTag(), WIRETYPE_FIXED64)
+                                                               + ":");
+                                               indent();
+                                               p(setter + 
"(input.readSFixed64());");
+                                       } else if 
(field.getTypeDescriptor().isEnum()) {
+                                               p("case " + 
makeTag(field.getTag(), WIRETYPE_VARINT)
+                                                               + ":");
+                                               indent();
+                                               String type = javaType(field);
+                                               p("{");
+                                               indent();
+                                               p("int t = input.readEnum();");
+                                               p("" + type + " value = " + 
type + ".valueOf(t);");
+                                               p("if( value !=null ) {");
+                                               indent();
+                                               p(setter + "(value);");
+                                               unindent();
+                                               p("}");
+                                               // TODO: else store it as an 
known
+
+                                               unindent();
+                                               p("}");
+
+                                       } else if (field.getGroup() != null) {
+                                               p("case "
+                                                               + 
makeTag(field.getTag(), WIRETYPE_START_GROUP)
+                                                               + ":");
+                                               indent();
+                                               String type = javaType(field);
+                                               if (repeated) {
+                                                       p(setter + 
"(readGroup(input, " + field.getTag()
+                                                                       + ", 
new " + type + "()));");
+                                               } else {
+                                                       p("if (has" + uname + 
"()) {");
+                                                       indent();
+                                                       p("readGroup(input, " + 
field.getTag() + ", get"
+                                                                       + uname 
+ "());");
+                                                       unindent();
+                                                       p("} else {");
+                                                       indent();
+                                                       p(setter + 
"(readGroup(input, " + field.getTag()
+                                                                       + ",new 
" + type + "()));");
+                                                       unindent();
+                                                       p("}");
+                                               }
+                                               p("");
+                                       } else {
+                                               p("case "
+                                                               + 
makeTag(field.getTag(),
+                                                                               
WIRETYPE_LENGTH_DELIMITED) + ":");
+                                               indent();
+                                               String type = javaType(field);
+                                               if (repeated) {
+                                                       p(setter + "(new " + 
type
+                                                                       + 
"().mergeFramed(input));");
+                                               } else {
+                                                       p("if (has" + uname + 
"()) {");
+                                                       indent();
+                                                       p("get" + uname + 
"().mergeFramed(input);");
+                                                       unindent();
+                                                       p("} else {");
+                                                       indent();
+                                                       p(setter + "(new " + 
type
+                                                                       + 
"().mergeFramed(input));");
+                                                       unindent();
+                                                       p("}");
+                                               }
+                                       }
+                                       p("break;");
+                                       unindent();
+                               }
+                               p("}");
+                       }
+                       unindent();
+                       p("}");
+               }
+               unindent();
+               p("}");
     }
 
     /**
-     * @param m
-     * @param className
-     */
+        * @param m
+        * @param className
+        */
     private void generateMethodMergeFromBean(MessageDescriptor m, String 
className) {
         p("public "+className+" mergeFrom("+className+" other) {");
         indent();
@@ -824,12 +994,12 @@
     }
 
     /**
-     * @param m
-     */
+        * @param m
+        */
     private void generateMethodClear(MessageDescriptor m) {
         p("public final void clear() {");
         indent();
-        p("memoizedSerializedSize=-1;");
+        p("super.clear();");
         for (FieldDescriptor field : m.getFields().values()) {
             String uname = uCamel(field.getName());
             p("clear" + uname + "();");
@@ -863,7 +1033,7 @@
         p("}");
         p();
         
-        p("private final "+className+" checktInitialized() throws 
com.google.protobuf.InvalidProtocolBufferException {");
+        p("protected final "+className+" checktInitialized() throws 
com.google.protobuf.InvalidProtocolBufferException {");
         indent();
         p("java.util.ArrayList<String> missingFields = missingFields();");
         p("if( !missingFields.isEmpty()) {");
@@ -878,6 +1048,9 @@
 
         p("public final java.util.ArrayList<String> missingFields() {");
         indent();
+        if( deferredDecode ) {
+               p("load();");
+        }        
         p("java.util.ArrayList<String> missingFields = new 
java.util.ArrayList<String>();");
         
         for (FieldDescriptor field : m.getFields().values()) {
@@ -891,41 +1064,43 @@
             }
         }
         
-        for (FieldDescriptor field : m.getFields().values()) {
-            if( field.getTypeDescriptor()!=null && 
!field.getTypeDescriptor().isEnum()) {
-                String uname = uCamel(field.getName());
-                p("if( has" + uname + "() ) {");
-                indent();
-                if( !field.isRepeated() ) {
-                    p("try {");
-                    indent();
-                    p("get" + uname + "().assertInitialized();");
-                    unindent();
-                    p("} catch 
(org.apache.activemq.protobuf.UninitializedMessageException e){");
-                    indent();
-                    
p("missingFields.addAll(prefix(e.getMissingFields(),\""+field.getName()+".\"));");
-                    unindent();
-                    p("}");
-                } else {
-                    String type = javaCollectionType(field);
-                    p("java.util.List<"+type+"> l = get" + uname + "List();");
-                    p("for( int i=0; i < l.size(); i++ ) {");
-                    indent();
-                    p("try {");
-                    indent();
-                    p("l.get(i).assertInitialized();");
-                    unindent();
-                    p("} catch 
(org.apache.activemq.protobuf.UninitializedMessageException e){");
-                    indent();
-                    
p("missingFields.addAll(prefix(e.getMissingFields(),\""+field.getName()+"[\"+i+\"]\"));");
-                    unindent();
-                    p("}");
-                    unindent();
-                    p("}");
-                }
-                unindent();
-                p("}");
-            }
+        if( !deferredDecode ) {
+               for (FieldDescriptor field : m.getFields().values()) {
+                   if( field.getTypeDescriptor()!=null && 
!field.getTypeDescriptor().isEnum()) {
+                       String uname = uCamel(field.getName());
+                       p("if( has" + uname + "() ) {");
+                       indent();
+                       if( !field.isRepeated() ) {
+                           p("try {");
+                           indent();
+                           p("get" + uname + "().assertInitialized();");
+                           unindent();
+                           p("} catch 
(org.apache.activemq.protobuf.UninitializedMessageException e){");
+                           indent();
+                           
p("missingFields.addAll(prefix(e.getMissingFields(),\""+field.getName()+".\"));");
+                           unindent();
+                           p("}");
+                       } else {
+                           String type = javaCollectionType(field);
+                           p("java.util.List<"+type+"> l = get" + uname + 
"List();");
+                           p("for( int i=0; i < l.size(); i++ ) {");
+                           indent();
+                           p("try {");
+                           indent();
+                           p("l.get(i).assertInitialized();");
+                           unindent();
+                           p("} catch 
(org.apache.activemq.protobuf.UninitializedMessageException e){");
+                           indent();
+                           
p("missingFields.addAll(prefix(e.getMissingFields(),\""+field.getName()+"[\"+i+\"]\"));");
+                           unindent();
+                           p("}");
+                           unindent();
+                           p("}");
+                       }
+                       unindent();
+                       p("}");
+                   }
+               }
         }
         p("return missingFields;");
         unindent();
@@ -945,6 +1120,9 @@
         p("public java.lang.StringBuilder toString(java.lang.StringBuilder sb, 
String prefix) {");
         indent();
         
+        if( deferredDecode ) {
+               p("load();");
+        }        
         for (FieldDescriptor field : m.getFields().values()) {
             String uname = uCamel(field.getName());
             p("if(  has" + uname + "() ) {");
@@ -1011,6 +1189,9 @@
             // Create the field accessors
             p("public boolean has" + uname + "() {");
             indent();
+            if( deferredDecode ) {
+               p("load();");
+            }        
             p("return this.f_" + lname + "!=null && !this.f_" + lname + 
".isEmpty();");
             unindent();
             p("}");
@@ -1018,6 +1199,9 @@
 
             p("public java.util.List<" + type + "> get" + uname + "List() {");
             indent();
+            if( deferredDecode ) {
+               p("load();");
+            }        
             p("if( this.f_" + lname + " == null ) {");
             indent();
             p("this.f_" + lname + " = new java.util.ArrayList<" + type + 
">();");
@@ -1030,6 +1214,7 @@
 
             p("public "+className+" set" + uname + "List(java.util.List<" + 
type + "> " + lname + ") {");
             indent();
+               p("loadAndClear();");
             p("this.f_" + lname + " = " + lname + ";");
             p("return this;");
             unindent();
@@ -1038,6 +1223,9 @@
             
             p("public int get" + uname + "Count() {");
             indent();
+            if( deferredDecode ) {
+               p("load();");
+            }        
             p("if( this.f_" + lname + " == null ) {");
             indent();
             p("return 0;");
@@ -1050,6 +1238,9 @@
             
             p("public " + type + " get" + uname + "(int index) {");
             indent();
+            if( deferredDecode ) {
+               p("load();");
+            }        
             p("if( this.f_" + lname + " == null ) {");
             indent();
             p("return null;");
@@ -1062,6 +1253,7 @@
                             
             p("public "+className+" set" + uname + "(int index, " + type + " 
value) {");
             indent();
+               p("loadAndClear();");
             p("get" + uname + "List().set(index, value);");
             p("return this;");
             unindent();
@@ -1070,6 +1262,7 @@
             
             p("public "+className+" add" + uname + "(" + type + " value) {");
             indent();
+               p("loadAndClear();");
             p("get" + uname + "List().add(value);");
             p("return this;");
             unindent();
@@ -1078,6 +1271,7 @@
             
             p("public "+className+" addAll" + uname + "(java.lang.Iterable<? 
extends " + type + "> collection) {");
             indent();
+               p("loadAndClear();");
             p("super.addAll(collection, get" + uname + "List());");
             p("return this;");
             unindent();
@@ -1086,6 +1280,7 @@
 
             p("public void clear" + uname + "() {");
             indent();
+               p("loadAndClear();");
             p("this.f_" + lname + " = null;");
             unindent();
             p("}");
@@ -1102,6 +1297,9 @@
             // Create the field accessors
             p("public boolean has" + uname + "() {");
             indent();
+            if( deferredDecode ) {
+               p("load();");
+            }        
             if (primitive) {
                 p("return this.b_" + lname + ";");
             } else {
@@ -1113,6 +1311,9 @@
 
             p("public " + type + " get" + uname + "() {");
             indent();
+            if( deferredDecode ) {
+               p("load();");
+            }        
             if( field.getTypeDescriptor()!=null && 
!field.getTypeDescriptor().isEnum()) {
                 p("if( this.f_" + lname + " == null ) {");
                 indent();
@@ -1127,6 +1328,7 @@
 
             p("public "+className+" set" + uname + "(" + type + " " + lname + 
") {");
             indent();
+               p("loadAndClear();");
             if (primitive) {
                 p("this.b_" + lname + " = true;");
             }
@@ -1138,6 +1340,7 @@
 
             p("public void clear" + uname + "() {");
             indent();
+               p("loadAndClear();");
             if (primitive) {
                 p("this.b_" + lname + " = false;");
             }


Reply via email to