I guess it's technically the case that a packed field always has non-zero size, but maybe we should initialize the cached sizes to -1 anyway to make it more clear when they haven't been initialized?
On Tue, Nov 24, 2009 at 7:04 PM, <jas...@google.com> wrote: > Reviewers: kenton, > > Description: > Fix Issue 136: the memoized serialized size for packed fields may not > be properly set. writeTo() may be invoked without a call to > getSerializedSize(), so the generated serialization methods would > write a length of 0 for non-empty packed fields. Since the object > is immutable, we know that the memoized size is 0 or set to the > correct size. In the generated code, check to see if the memoized > size is 0, and if so, call getSerializedSize() before actually > emitting the field. > > Tested: new unittest case in WireFormatTest.java now passes > > > > Please review this at http://codereview.appspot.com/157169 > > Affected files: > M java/src/test/java/com/google/protobuf/WireFormatTest.java > M src/google/protobuf/compiler/java/java_primitive_field.cc > > > Index: java/src/test/java/com/google/protobuf/WireFormatTest.java > =================================================================== > --- java/src/test/java/com/google/protobuf/WireFormatTest.java (revision > 246) > +++ java/src/test/java/com/google/protobuf/WireFormatTest.java (working > copy) > @@ -102,6 +102,28 @@ > assertEquals(rawBytes, rawBytes2); > } > > + public void testSerializationPackedWithoutGetSerializedSize() > + throws Exception { > + // Write directly to an OutputStream, without invoking > getSerializedSize() > + // This used to be a bug where the size of a packed field was > incorrect, > + // since getSerializedSize() was never invoked. > + TestPackedTypes message = TestUtil.getPackedSet(); > + > + // Directly construct a CodedOutputStream around the actual > OutputStream, > + // because writeTo() now invokes getSerializedSize(); > + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); > + CodedOutputStream codedOutput = > CodedOutputStream.newInstance(outputStream); > + > + message.writeTo(codedOutput); > + > + codedOutput.flush(); > + > + TestPackedTypes message2 = TestPackedTypes.parseFrom( > + outputStream.toByteArray()); > + > + TestUtil.assertPackedFieldsSet(message2); > + } > + > public void testSerializeExtensionsLite() throws Exception { > // TestAllTypes and TestAllExtensions should have compatible wire > formats, > // so if we serialize a TestAllExtensions then parse it as TestAllTypes > Index: src/google/protobuf/compiler/java/java_primitive_field.cc > =================================================================== > --- src/google/protobuf/compiler/java/java_primitive_field.cc (revision > 246) > +++ src/google/protobuf/compiler/java/java_primitive_field.cc (working > copy) > @@ -384,8 +384,17 @@ > void RepeatedPrimitiveFieldGenerator:: > GenerateSerializationCode(io::Printer* printer) const { > if (descriptor_->options().packed()) { > + // writeTo() may be called without getSerializedSize() ever having > been > + // called, so we may need to compute the length of the packed data. > Since > + // the object is immutable, we know that the memoized size is either > set to > + // 0 (via object initialization) or else it has the correct size from > a > + // previous getSerializedSize() call. If the field is not empty and > the size > + // has not yet been computed, just call getSerializedSize() > printer->Print(variables_, > "if (get$capitalized_name$List().size() > 0) {\n" > + " if ($name$MemoizedSerializedSize == 0) {\n" > + " getSerializedSize();\n" > + " }\n" > " output.writeRawVarint32($tag$);\n" > " output.writeRawVarint32($name$MemoizedSerializedSize);\n" > "}\n" > > > -- You received this message because you are subscribed to the Google Groups "Protocol Buffers" group. To post to this group, send email to proto...@googlegroups.com. To unsubscribe from this group, send email to protobuf+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/protobuf?hl=en.