Return-Path: Delivered-To: apmail-activemq-commits-archive@www.apache.org Received: (qmail 6351 invoked from network); 8 Oct 2008 23:33:09 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 8 Oct 2008 23:33:09 -0000 Received: (qmail 28890 invoked by uid 500); 8 Oct 2008 23:33:08 -0000 Delivered-To: apmail-activemq-commits-archive@activemq.apache.org Received: (qmail 28871 invoked by uid 500); 8 Oct 2008 23:33:08 -0000 Mailing-List: contact commits-help@activemq.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@activemq.apache.org Delivered-To: mailing list commits@activemq.apache.org Received: (qmail 28862 invoked by uid 99); 8 Oct 2008 23:33:08 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 08 Oct 2008 16:33:08 -0700 X-ASF-Spam-Status: No, hits=-1999.9 required=10.0 tests=ALL_TRUSTED,DNS_FROM_SECURITYSAGE X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 08 Oct 2008 23:32:11 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 9A8D62388886; Wed, 8 Oct 2008 16:32:17 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r703019 - in /activemq/sandbox/activemq-protobuf: activemq-protobuf-test/src/main/proto/ activemq-protobuf-test/src/test/java/org/ activemq-protobuf-test/src/test/java/org/apache/ activemq-protobuf-test/src/test/java/org/apache/activemq/ ac... Date: Wed, 08 Oct 2008 23:32:16 -0000 To: commits@activemq.apache.org From: chirino@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20081008233217.9A8D62388886@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org 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 extends BaseMessage{ + + 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 errors = new ArrayList(); 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 missingFields = missingFields();"); p("if( !missingFields.isEmpty()) {"); @@ -878,6 +1048,9 @@ p("public final java.util.ArrayList missingFields() {"); indent(); + if( deferredDecode ) { + p("load();"); + } p("java.util.ArrayList missingFields = new java.util.ArrayList();"); 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 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;"); }